/******************************************************************************* * * (C) COPYRIGHT MICROSOFT CORPORATION, 1998 * * TITLE: 32BITDIB.H * * VERSION: 1.0 * * AUTHOR: t-JacobR * * DATE: 1/11/2000 * * DESCRIPTION: * * C32BitDibWrapper provides support for a number of common graphics special * effects for this class, 32 bit dibs are stored in the following format: 8 * ignored high order bits followed by 8 bits per RGB chan. warning: many * functions in this class will reset the 8 high order bits so it is not * practical to add additional functions which use an 8 bit alpha chan * * Notes: * * The blur function is designed so that it can be combined with the * difference function to create an edge detection filter More specifically, * the blur function takes the average of only the four pixels around the * current pixel instead of including the current pixel in the average. * *******************************************************************************/ #ifndef __32BITDIB_H_INCLUDED #define __32BITDIB_H_INCLUDED // // Constants used for Region Detection // #define MERGE_REGIONS TRUE #define MAXREGIONS 10000 #define PHOTOGRAPH_REGION 1 #define TEXT_REGION 2 // // We don't want lowlife text regions which are probably stray dots merging with // photograph regions this id certifies that a text region is big enough to merge // with a photograph // #define MERGABLE_WITH_PHOTOGRAPH 16 // // how many pixels before you are too big to even imagine that you are a stray blot // #define LARGEREGION_THRESHOLD 10000 // // pixels // #define MINREGIONSIZE 10 // // how far down should we sample the the image? // goal to sample down the image to // #define GOALX 300 #define GOALY 400 // // borderline in function between text regions and photo regions // #define MIN_BORDERLINE_TEXTPHOTO 10 // // If in borderline, we apply extra functions to determine if its really // a text region or not // #define TEXTPHOTO_THRESHOLD 15 #define MAX_BORDERLINE_TEXTPHOTO 1500 // // Note... we won't consider merging two photo regions if both regions // are greater than MAX_MERGABLE_PHOTOGRAPH_SIZE // #define MAX_MERGE_PHOTO_REGIONS 2 #define MAX_NO_EDGE_PIXEL_REGION_PENALTY 16 // // Maximum merge radius for regions where one region is text and one is a photo region // #define MAX_MERGE_DIFFERENT_REGIONS 13 // // If you are close to the edge after this long you very well might be a stray blot // #define BORDER_EXTREME_EDGE_PIXEL_REGION_PENALTY 45 // // maximum merging radius for text regions merged with text regions // note: no merging takes place between photo regions and photo regions // #define MAXBORDER 65 // // maximum border width where we can look the other way when it comes to // collision detection collsion detection is somewhat expensive so only use // it when we are dealing with signifigant spacings. we only want to use // collision detection to make sure that we don't create regions through // previously deleted shadows, etc. constants for deciding if a region is a // valid region // // NOTE: we never do collision detection for merging photo regions... for // obvious reasons... we only want to merge photo regions which are part of // the same region... hence we would actually only want to merge photograph // regions where there was a pretty high collision factor // #define MERGABLE_WITHOUT_COLLISIONDETECTION 668 // // minimum region width // #define MINWIDTH 5 #define MINPHOTOWIDTH 5 // // maximum ratio between height and width // #define MAXREGIONRATIO 81 #define MAXPHOTORATIO 81 #define MINSIZE 30 // // if you are more than 6 pixels wide, you are ok. we don't care what your aspect ratio is // #define IGNORE_RATIO_WIDTH 6 // // number of pixels required before we throw a region out as being just a // stray dot (10 x 10 so it isn't a huge requirement) // #define MINREGIONPIXELS 20 // // very conservative // #define MINPPHOTOSELECTEDFACTOR 5 // // conservative.. its unlikely that many regions will have edge factors this low // #define MINEDGEFACTOR 5 // // allow a couple of black pixels without going crazy // #define MAX_RESISTANCE_ALLOWED_TO_UNION 1024 #define DONE_WITH_BORDER_CHECKING -1 #define MIN_FINAL_REGION_SIZE 38 #define CLOSE_TO_EDGE_PENALTY_WIDTH 3 // // the following are designed to weed out speckles. these are only applied // after we have increased the border past MAX_MERGE_DIFFERENT_REGIONS. so // all that should be left is small text regions and long and narrow // speckles. // // // no close to edge penalty factor // #define CLOSE_TO_EDGE_PENALTY_FACTOR 1 #define UNKNOWN -1 #define EDGE_PENALTY_WIDTH 2 // // 2x all requirements if region is within EDGE_PENALTY_WIDTH from the edge // of the image. some requirements may be multiplied by EDGE_PENALTY_FACTOR // squared... i.e. for 2D requirments like num of pixels // #define EDGE_PENALTY_FACTOR 1 #define COMPARISON_ERROR_RADIUS 2 // // constants used for findchunk filters so that we aren't lead astray by the // possible black ring around the image // #define VERTICAL_EDGE -1 #define HORIZONTAL_EDGE -2 // // a nice massive stack which is large enough that we are gauranteed never to exceed it // #define MAXSTACK (GOALX*GOALY) // // we do two remove shadow passes. // one pass is intended to only remove shadows // the other is designed to handle scanners which have yellow lids, etc. // // // maximum intensity allowed for first pixel of a shadow.. we used to // think that we should only let shadows start at 0... that was before we // saw the light // #define MAXSHADOWSTART 800 // // maximum edge value permitted for a shadow pixel // #define MAXSHADOWPIXEL 3 // // if we are near the edge, we want to kill anything that is remotely like a shadow // #define MAXEDGESHADOWPIXEL 20 #define MAX_DIFFERENCE_FROM_GRAY 690 // // border where we do tougher despeckle & edge filters... // #define DESPECKLE_BORDER_WIDTH 6 // // the background color remove shadows algorithm pass is at the moment the // same as the first pass. we may later want to optumize it to better do its // specific task.. for example... for this filter, we could care less about // if a pixel isn't grey // // // accept all pixels // #define FIX_BACKGROUND_MAXSHADOWSTART 800 #define FIX_BACKGROUND_MAXSHADOWPIXEL 2 // // maximum intensity to be considered a bonified text region background pixel // #define TEXT_REGION_BACKGROUND_THRESHOLD 31 // // this if for use with Pixels below Threshold which should be called using // the origional image... not an inverted image // // // minimum edge value to earn the distinguished title of being a text region edge pixel // #define MIN_TEXT_REGION_BACKGROUND_EDGE 32 // // minimum edge value to earn the distinguished title of being a text region edge pixel // #define MIN_TEXT_REGION_BACKGROUND_EDGE_CLIPPED_PIXEL 120 #define CLIPPED_TEXT_REGION_BACKGROUND_THRESHOLD 180 // // not implemented yet // #define TEXT_REGION_BACKGROUND_PIXEL_MAX_CLIPPED_DIFFERENCE_FROM_GREY 32 // // minimum intensity to select a pixel // #define MIN_CHUNK_INTENSITY 48 // // should be 0, but different values are useful for debugging... although // extreme values will potentially mess up region detection its the color we // set erased shadow bits // #define ERASEDSHADOW 0 // beta constants: // // idea: inverted images... and constant color image potential problems // #define COLLISION_DETECTION_HIGHPASS_VALUE 600 // // if a photograph gets fragmented we will see a bunch of closely spaced and // relatively small regions only one of the two regions has to be bellow this // size requirement to merge them as part way through the merge proccess we // will be definition have a larger region than this const or the const isn't // fullfilling its purpose // #define MAX_MERGABLE_PHOTOGRAPH_SIZE 30000 #define NOT_SHADOW 0x800ff09 // // a pixel which we are sure is bad and that we will no // rejuvinate no matter that edge val it may have // #define DEAD_PIXEL 0x8000002 // // minimum edge intensity to classify a pixel as NOT_SHADOW // #define NOT_SHADOW_INTENSITY 28 #define MIN_WALL_INTENSITY 200 #define MIN_BLACK_SCANNER_EDGE_CHAN_VALUE 110 #define MAX_BLACK_BORDER_DELTA 12 #define MAX_KILL_SHADOW_BACKGROUND_APROXIMATION 64 #define MAX_KILL_SHADOW_BACKGROUND_UNEDITED 200 // // further ideas: to eliminate the possibility of embarassing errors: count // the number of background pixels if the num of background pixels is above a // threshold use weaker shadow and edge filters as we probably have a good // scanner something like if half the page is defined as background pixels // dangers: white page on a horrible scanner // // // MORE IMPORTANTLY: also the select region search radius TIP: if you are // running multiple region selection, an EDGEWIDTH of 3 or more could limit // your options considerably as nearby regions may get merged together // particularly when using edge enhancement and when GOALX is set at 300 or // less // #define EDGEWIDTH 2 // // color used to highlight clipped pixels while debugging the code for eliminating black borders // #define DEBUGCOLOR 0xff0000 #define FIGHTING_EDGES FALSE // // you better be darn close to grey to get marked as NOT_SHADOW fighting // edges involve pixeled being marked as not possibly being edges as well as // pixels // #define FIGHTING_EDGES_DIFF_FROM_GREY 10 // // being marked as definite edges // #define FIGHTING_EDGE_MIN_MARK_PIXEL 10 #define FIGHTING_EDGE_MAX_MARK_PIXEL 210 #define FIGHTING_EDGE_MAX_EDGE 1 #define BORDER_EDGE 0xfffffff // // used for killing the black border around the page // #define CORNER_WIDTH 5 // // used for black border removal // #define SHADOW_HEIGHT 10 #define VISUAL_DEBUG FALSE #define SMOOTH_BORDER FALSE // // amount to increase border while unioning together regions for single region // region detection // #define SINGLE_REGION_BORDER_INCREMENT 4 class C32BitDibWrapper { private: // // No implementation // C32BitDibWrapper &operator=( const C32BitDibWrapper & ); C32BitDibWrapper( const C32BitDibWrapper & ); public: explicit C32BitDibWrapper(BITMAP pBitmap); // // Copy constructor... create a new dib wrapper with a copy of all the data in the other dib wrapper // explicit C32BitDibWrapper(C32BitDibWrapper *pBitmap); // // construct wrapper from a dib // explicit C32BitDibWrapper(BYTE* pDib); // // creates an uninitialized dib wrapper // C32BitDibWrapper(void); // // creates a blank dib // C32BitDibWrapper(int w, int h); virtual ~C32BitDibWrapper(void); void Destroy(void); // // functions for common graphics effects // int Blur(void); BYTE* pointerToBlur(void); BYTE* pointerToHorizontalBlur(void); BYTE* pointerToVerticalBlur(void); int CreateBlurBitmap(C32BitDibWrapper * pSource); int CreateHorizontalBlurBitmap(C32BitDibWrapper * pSource); int CreateVerticalBlurBitmap(C32BitDibWrapper * pSource); // // Creates a new dib where each pixel is equal to the difference // of the pixel values for the other two dibs // int CreateDifferenceBitmap (C32BitDibWrapper *pBitmap1, C32BitDibWrapper *pBitmap2); int KillShadows(C32BitDibWrapper * pEdgeBitmap, ULONG start, ULONG maxPixel, ULONG differenceFromGrey, ULONG min_guaranteed_not_shadow, bool enhanceEdges); void RemoveBlackBorder(int minBlackBorderPixel, C32BitDibWrapper * outputBitmap,C32BitDibWrapper * debugBitmap); // // resample image down to half size // int HalfSize(void); // // resample image down to half intensity // int HalfIntensity(void); void Invert(void); // // less common graphics filters: // void Despeckle(void); // // only despeckle the outer edge of pixels in the image // void EdgeDespeckle(void); // // despeckles the ith pixel in a bitmap // void DespecklePixel(ULONG* bitmapPixels, int i, bool edgePixel); void CorrectBrightness(void); void MaxContrast(UINT numPixelsRequired); void AdjustForBadScannerBedColor(C32BitDibWrapper * edgeBitmap); // // Similar to a photoshop magic wand.. just we try to run our magic wand starting from ever possible pixel // int FindChunks(int * pMap); // // display selected chunks... for debugging purposes mostly // void ColorChunks(int * pMap); int PixelsBelowThreshold(C32BitDibWrapper* pProccessed, C32BitDibWrapper * pEdges, RECT region); BYTE* ConvertBitmap(BYTE* pSource, int bitsPerSource, int bitsPerDest); // // for debugging purposes only // MyBitBlt is horribly slow as we manually convert the // bitmap to a 24 bit dib before displaying // int Draw(HDC hdc, int x, int y); inline void SetPixel(int x, int y, ULONG color); inline ULONG GetPixel(int x, int y); // // calculates the total color intensity of a line // ULONG Line(int x1, int y1, int x2, int y2); private: // // line drawing helper functions // ULONG Octant0(int X0, int Y0,int DeltaX,int DeltaY,int XDirection); ULONG Octant1(int X0, int Y0,int DeltaX,int DeltaY,int XDirection); // // kill borders helper function: // void KillBlackBorder(int minBlackBorderPixel, int startPosition, int width, int height, int dx, int dy, C32BitDibWrapper *pOutputBitmap, C32BitDibWrapper * pDebugBitmap); public: void CompensateForBackgroundColor(int r, int g, int b); ULONG CalculateBackgroundColor(void); bool IsValid(void) { return (m_pBits && m_nBitmapWidth != -1 && m_nBitmapHeight != -1); } public: BYTE *m_pBits; int m_nBitmapWidth; int m_nBitmapHeight; }; // // dib manipulation functions // void SetBMI( PBITMAPINFO pbmi, LONG width, LONG height, LONG depth ); PBYTE AllocDibFileFromBits( PBYTE pBits, UINT width, UINT height, UINT depth ); HBITMAP DIBBufferToBMP( HDC hDC, PBYTE pDib, BOOLEAN bFlip ); HRESULT ReadDIBFile( LPTSTR pszFileName, PBYTE *ppDib ); LONG GetBmiSize( PBITMAPINFO pbmi ); INT GetColorTableSize( UINT uBitCount, UINT uCompression ); DWORD CalcBitsSize( UINT uWidth, UINT uHeight, UINT uBitCount, UINT uPlanes, int nAlign ); HGLOBAL BitmapToDIB( HDC hdc, HBITMAP hBitmap ); #endif // __32BITDIB_H_INCLUDED