这是以前应朋友邀请写的算法,大多数是基础的,只是由于长时间不写,显得生疏,不知道是否有用,贴出来帮给初学者参考。算法是在MFC框架下编写的,我会把主文件和相关文件相继贴出来。
一、基本实现如下功能:
1) 图像灰度图、彩色图和二值化三种格式文件的打开和存储功能;
2) 支持版面局部纠偏功能;
3) 图像去污功能;
4) 支持图像局部浓淡调整功能;
5) 支持去除图像黑白边功能;
6) 支持部分磨白功能;
7) 擦除图像功能;
8) 自动和人工二值化功能;
9) 对图像提供横、竖拆页功能,图像人工、自动拼页功能;
10) 图像进行左、右旋转,翻转及改变图像亮度操作功能;
二、主函数为CArdpsImg类
1)头文件
#pragma once
#include "api/dibapi.h"
#include "api/ImgConv.h"
#include "api/CompConnect.h"
class CArdpsImg : public CObject
{
DECLARE_SERIAL(CArdpsImg)
public:
CArdpsImg(void);
CArdpsImg &operator =(const CArdpsImg &ArdSrc);
CArdpsImg(const CArdpsImg &ArdSrc);
HANDLE LoadNonDibHandle(BOOL *bBmp, char* szImgFileName);
bool ConvertGray(int nMethod, UINT uiRWeight = 114, UINT uiGWeight = 587, UINT uiBWeight = 299 );
bool ConvertBinary(int nMethod /* = 0 */, int nTh /* = 0 */);
bool SaveNonDIB(HDIB hDib, CString strFileName, ImageType nDestFileExtType );
bool GrayEqual();
bool GrayStretch(int nMethod, BYTE x1,BYTE y1,BYTE x2,BYTE y2);
bool EliminateDirt(int nMethod, const CRect rct);
bool EliminateDirt(int nMethod, const int nCircleX, const int nCircleY, const int nRadius);
void SetDirtSize(CSize szMax, CSize szMin);
CRect* GetDirtPos( int nMethod, int *nCnt);
bool AutoEliminateDirt(int nMethod, int nMinArea);
bool AutoEliminateDirt(int nMethod, CRect *pRect, int *pFlag, const int nNum);
bool RotateImage(int iRotateAngle = 0);
bool AutoRotatelImage( RECT rtROI);
bool CutFrame();
bool SplitImage(POINT pt1, POINT pt2, CArdpsImg *pNewArd);
bool MergeImage(CArdpsImg *pSrcArd, int nMethod = 0);
bool MergeImage(CArdpsImg *pSrcArd, int nPos1, int nPos2, int nMethod = 0);
bool SaveTiff(char *szImgFileName);
bool AjustLightAndContrast(int brightness, int contrast);
bool Zoom(double fRatioX, double fRatioY);
bool AdjustBinPos( int nMethod = 0);
bool ColorEqual();
bool SaveGrayDIB(); // for debug
void Serialize(CArchive& ar);
bool IsEmpty();
bool Read(CFile *pFile);
bool Write(CFile *pFile);
bool Create(LPBYTE lpDIB);
bool Create(LPBYTE lpDIB, WORD wBitCount);
bool UpdateInternal();
void Destroy();
bool BuildBitmap();
bool BuildPalette();
bool Display(CDC* pDC, int x, int y, DWORD dwRop=SRCCOPY);
bool ConvertFormat(WORD wBitCount);
WORD GetBitCount();
LONG GetWidth();
LONG GetHeight();
LONG GetWidthBytes();
WORD GetPaletteSize();
HANDLE GetHandle();
WORD GetColorNumber();
LPBYTE GetBitsPtr();
bool Attach(HDIB hDib);
ImageType GetFileExtType(CString strExt);
CPalette* GetPalette();
private:
bool InitDIBFileHead(LPBITMAPINFOHEADER lpBI, BITMAPFILEHEADER *lpbmfHdr);
bool IntensityMean(const BYTE *pbGray, const int nImgWid, const int nImgHei, int &nIntenMean );
bool ThreshImage(const BYTE *pbImg, BYTE *pbBinary, const int nImgWid, const int nImgHei, const int nTh);
void OtsuTh( DWORD nW, DWORD nH, BYTE *lpBits, int &Th);
void ExtractComponent(Line * Li, BYTE *pMotion, UINT grayBytesPerLine, BYTE bCur ) ;
inline void add(int a,int b,char **flag,int *&stack,int **InStack, int &top,int &topin,int c,int d,component *ctail, BYTE *pMotion, UINT grayBytesPerLine, BYTE bCur );
void AnalysisComponent( Line * Li, BYTE *pbBinary, UINT unBinaryBytesPerLine, UINT minArea, const BYTE bValue);
bool AnalysisDirtPos(Line *Li, CSize maxSize, CSize minSize, int nHeight, int *nCnt);
bool ConvertBinary2Gray(const unsigned char * pbBinary, const int nWidth, const int nHeight, unsigned char *pbGray);
void SetBinary(CRect rect, BYTE *pbImg, UINT unBinaryBytesPerLine, const BYTE bValue);
int OutputNormalImageUnderAngle(BYTE *DesImg, const BYTE *SrcImage, int nWidth, int nHeight, double dk);
bool FindTopEdge(BYTE *pbOutImage, BYTE *image, RECT rtROI, int nWidth);
double DetectSkewAngle(BYTE *pbImage, RECT rtROI, int nWidth);
RECT GetEdgeImageBoundary(BYTE *pbImage, int nWidth, int nHeight);
RECT GetBinImageBoundary(BYTE *pbImage, int nWidth, int nHeight);
int FindEdgeImage(BYTE *pbOutImage, BYTE *image, RECT rtROI, int nWidth);
RECT SetRectValue(int left, int right, int top, int bottom);
bool VerticalSplit(int nX, CArdpsImg *newArt);
bool HorizntalSplit(int nY, CArdpsImg *newArt);
int CompVPrjValeSum(int *pnRamBuff, const BYTE *pInImg, int nImgWidth, int nImgHeight, int nRotAngle);
void SmoothingArray(int *pOut, int nR, const int *pIn, int nStart, int nEnd) ;
int DeleteVtlSmallLine(BYTE* pImg, BYTE* pBuf, int nWidth, int nHeight, int nTh);
HDIB ReadBinTiff(char* szImgFileName);
void Img32to24(BYTE *pbImg32, BYTE *pbImg24, int nWidth, int nHeight);
void ReversBits(BYTE *pbIn, int nWidth, int nHeight, DWORD nBitCnt);
void ReversColors(BYTE*pbIn, BYTE *pbOut, int nWidth, int nHeight);
void ReversColors(BYTE*pbIn, int nWidth, int nHeight);
void MoveBin(BYTE *pbIn, int nWidth, int nHeight, RECT rtOld, RECT rtNew, int nMethod = 0);
public:
HDIB m_hDib; //DIB handle of CDib object
HBITMAP m_hBitmap; // handle of DIBSection
CPalette* m_pPalette; //related to DIB's palette CPalette object
CBitmap* m_pBitmap; //related to DDB's CBitmap object
HDIB m_hNewDib;
// private member data
private:
// for drawing in DIB
CDC * m_pMemDC;
CBitmap* m_pBitmapTmp;
CPalette* m_pPaletteTmp;
CSize m_DirtSize;
CSize m_minDirtSize;
CRect *m_dirRect;
public:
virtual ~CArdpsImg(void);
};
2)源文件
#include "StdAfx.h"
#include "ArdpsImg.h"
#include "api/ImgConv.h"
#include "api/CompConnect.h"
#include "api/tiff/tiffio.h"
#include <stdlib.h>
#include <time.h>
#include <math.h>
#include <windowsx.h> // especially for GlobalAllocPtr
const UINT uiRWeight = 114;
const UINT uiGWeight = 587;
const UINT uiBWeight = 299;
#define PI 3.14159
//角度到弧度转化的宏
#define RADIAN(angle) ((angle)*PI/180.0)
#define EDGE_STEP 4
DWORD buf[256];
double bufi[256], varience[256];
// 5. the cos value(*65536 or * (2**16)) with angle from 0 to 180 and the step is 1
const int g_nCos[180] = {
65536, 65526, 65496, 65446, 65376, 65286, 65176, 65047, 64898, 64729,
64540, 64331, 64103, 63856, 63589, 63302, 62997, 62672, 62328, 61965,
61583, 61183, 60763, 60326, 59870, 59395, 58903, 58393, 57864, 57319,
56755, 56175, 55577, 54963, 54331, 53683, 53019, 52339, 51643, 50931,
50203, 49460, 48702, 47930, 47142, 46340, 45525, 44695, 43852, 42995,
42125, 41243, 40347, 39440, 38521, 37589, 36647, 35693, 34728, 33753,
32768, 31772, 30767, 29752, 28729, 27696, 26655, 25606, 24550, 23486,
22414, 21336, 20251, 19160, 18064, 16961, 15854, 14742, 13625, 12504,
11380, 10252, 9120, 7986, 6850, 5711, 4571, 3429, 2287, 1143,
0, -1143, -2287, -3429, -4571, -5711, -6850, -7986, -9120, -10252,
-11380, -12504, -13625, -14742, -15854, -16961, -18064, -19160, -20251, -21336,
-22414, -23486, -24550, -25606, -26655, -27696, -28729, -29752, -30767, -31772,
-32768, -33753, -34728, -35693, -36647, -37589, -38521, -39440, -40347, -41243,
-42125, -42995, -43852, -44695, -45525, -46340, -47142, -47930, -48702, -49460,
-50203, -50931, -51643, -52339, -53019, -53683, -54331, -54963, -55577, -56175,
-56755, -57319, -57864, -58393, -58903, -59395, -59870, -60326, -60763, -61183,
-61583, -61965, -62328, -62672, -62997, -63302, -63589, -63856, -64103, -64331,
-64540, -64729, -64898, -65047, -65176, -65286, -65376, -65446, -65496, -65526
};
// 6. the sin value(*65536 or * (2**16)) with angle from 0 to 180 and the step is 1
const int g_nSin[180] = {
0, 1143, 2287, 3429, 4571, 5711, 6850, 7986, 9120, 10252,
11380, 12504, 13625, 14742, 15854, 16961, 18064, 19160, 20251, 21336,
22414, 23486, 24550, 25606, 26655, 27696, 28729, 29752, 30767, 31772,
32768, 33753, 34728, 35693, 36647, 37589, 38521, 39440, 40347, 41243,
42125, 42995, 43852, 44695, 45525, 46340, 47142, 47930, 48702, 49460,
50203, 50931, 51643, 52339, 53019, 53683, 54331, 54963, 55577, 56175,
56755, 57319, 57864, 58393, 58903, 59395, 59870, 60326, 60763, 61183,
61583, 61965, 62328, 62672, 62997, 63302, 63589, 63856, 64103, 64331,
64540, 64729, 64898, 65047, 65176, 65286, 65376, 65446, 65496, 65526,
65536, 65526, 65496, 65446, 65376, 65286, 65176, 65047, 64898, 64729,
64540, 64331, 64103, 63856, 63589, 63302, 62997, 62672, 62328, 61965,
61583, 61183, 60763, 60326, 59870, 59395, 58903, 58393, 57864, 57319,
56755, 56175, 55577, 54963, 54331, 53683, 53019, 52339, 51643, 50931,
50203, 49460, 48702, 47930, 47142, 46340, 45525, 44695, 43852, 42995,
42125, 41243, 40347, 39440, 38521, 37589, 36647, 35693, 34728, 33753,
32768, 31772, 30767, 29752, 28729, 27696, 26655, 25606, 24550, 23486,
22414, 21336, 20251, 19160, 18064, 16961, 15854, 14742, 13625, 12504,
11380, 10252, 9120, 7986, 6850, 5711, 4571, 3429, 2287, 1143
};
typedef bool (*PFN_ImageConvert)(const unsigned char * pSrcData, int nSrcDataLen, ImageType itSrcImageType,
unsigned char * * ppDestData, int * pnDestDataLen, ImageType itDestImageType);
typedef bool (*PFN_ImageDelete)(unsigned char * * ppImageData);
IMPLEMENT_SERIAL(CArdpsImg, CObject, 0)
CArdpsImg::CArdpsImg(void)
{
m_hDib = NULL; //CDib对象所表示的DIB句柄
m_hBitmap = NULL; //DIB对应的DIBSECTION的句柄
m_pPalette = NULL; //和DIB相关的CPalette调色板对象
m_pBitmap = NULL; //和DIB相关的CBitmap DDB对象
m_hNewDib = NULL;
m_DirtSize.cx = 5;
m_DirtSize.cy = 5;
m_minDirtSize.cx = 2;
m_minDirtSize.cy = 2;
m_dirRect = NULL;
}
CArdpsImg::CArdpsImg(const CArdpsImg &ArdSrc)
{
if (this != &ArdSrc)
{
Destroy();
if (m_pBitmap != NULL)
{
delete m_pBitmap;
m_pBitmap = NULL;
}
if (m_pPalette != NULL)
{
delete m_pPalette;
m_pPalette = NULL;
}
if( m_dirRect )
{
delete []m_dirRect;
m_dirRect = NULL;
}
if ( m_pMemDC )
{
delete m_pMemDC;
m_pMemDC = NULL;
}
this->m_hDib = ArdSrc.m_hDib;
this->m_hNewDib = ArdSrc.m_hNewDib;
this->m_pBitmap = ArdSrc.m_pBitmap;
this->m_pPalette = ArdSrc.m_pPalette;
this->m_dirRect = ArdSrc.m_dirRect;
this->m_pMemDC = ArdSrc.m_pMemDC;
this->m_pPaletteTmp = ArdSrc.m_pPaletteTmp;
this->m_pBitmapTmp = ArdSrc.m_pBitmapTmp;
this->m_DirtSize = ArdSrc.m_DirtSize;
this->m_minDirtSize = ArdSrc.m_minDirtSize;
this->m_dirRect = ArdSrc.m_dirRect;
}
}
CArdpsImg::~CArdpsImg(void)
{
Destroy();
if (m_pBitmap != NULL)
{
delete m_pBitmap;
m_pBitmap = NULL;
}
if (m_pPalette != NULL)
{
delete m_pPalette;
m_pPalette = NULL;
}
if( m_dirRect )
{
delete []m_dirRect;
m_dirRect = NULL;
}
}
CArdpsImg & CArdpsImg::operator =(const CArdpsImg &ArdSrc)
{
if (this != &ArdSrc)
{
Destroy();
if (m_pBitmap != NULL)
{
delete m_pBitmap;
m_pBitmap = NULL;
}
if (m_pPalette != NULL)
{
delete m_pPalette;
m_pPalette = NULL;
}
if( m_dirRect )
{
delete []m_dirRect;
m_dirRect = NULL;
}
if ( m_pMemDC )
{
delete m_pMemDC;
m_pMemDC = NULL;
}
this->m_hDib = ArdSrc.m_hDib;
this->m_hNewDib = ArdSrc.m_hNewDib;
this->m_pBitmap = ArdSrc.m_pBitmap;
this->m_pPalette = ArdSrc.m_pPalette;
this->m_dirRect = ArdSrc.m_dirRect;
this->m_pMemDC = ArdSrc.m_pMemDC;
this->m_pPaletteTmp = ArdSrc.m_pPaletteTmp;
this->m_pBitmapTmp = ArdSrc.m_pBitmapTmp;
this->m_DirtSize = ArdSrc.m_DirtSize;
this->m_minDirtSize = ArdSrc.m_minDirtSize;
this->m_dirRect = ArdSrc.m_dirRect;
}
return *this;
}
void CArdpsImg::Serialize(CArchive& ar)
{
CObject::Serialize(ar);
ar.Flush();
if (ar.IsStoring())
{
Write(ar.GetFile());
}
else
{
Read(ar.GetFile());
}
}
bool CArdpsImg::Read(CFile *pFile)
{
WaitCursorBegin();
LPBITMAPINFOHEADER lpbi;
DWORD dwSize;
TRY
{
// read DIB file header
BITMAPFILEHEADER bmfHdr;
pFile->Read(&bmfHdr, sizeof(BITMAPFILEHEADER));
// is DIB file?
if (bmfHdr.bfType != DIB_HEADER_MARKER/*"BM"*/)
{
WaitCursorEnd();
return false;
}
DWORD dwLength = pFile->GetLength();
if (bmfHdr.bfSize != dwLength)
bmfHdr.bfSize = dwLength;
// read DIB buffer
dwSize = bmfHdr.bfSize - sizeof(BITMAPFILEHEADER);
lpbi = (LPBITMAPINFOHEADER)GlobalAllocPtr(GHND, dwSize);
DWORD dwCount = pFile->Read(lpbi, dwSize);
// read ok?
if (dwCount != dwSize)
{
GlobalFreePtr(lpbi);
WaitCursorEnd();
return false;
}
// Check to see that it's a Windows DIB -- an OS/2 DIB would cause
// strange problems with the rest of the DIB API since the fields
// in the header are different and the color table entries are
// smaller.
//
// If it's not a Windows DIB (e.g. if biSize is wrong), return NULL.
if (lpbi->biSize != sizeof(BITMAPINFOHEADER))
{
GlobalFreePtr(lpbi);
WaitCursorEnd();
return false;
}
// fill color num item
int nNumColors = (UINT)lpbi->biClrUsed;
if (nNumColors == 0)
{
// no color table for 24-bit, default size otherwise
if (lpbi->biBitCount != 24)
nNumColors = 1 << lpbi->biBitCount; // standard size table
}
// fill in some default values if they are zero
if (lpbi->biClrUsed == 0)
lpbi->biClrUsed = nNumColors;
if (lpbi->biSizeImage == 0)
lpbi->biSizeImage = ((((lpbi->biWidth * (DWORD)lpbi->biBitCount) + 31) & ~31) >> 3) * lpbi->biHeight;
}
CATCH (CException, e)
{
GlobalFreePtr(lpbi);
WaitCursorEnd();
return false;
}
END_CATCH
// create CDib with DIB buffer
bool bSuccess = Create((LPBYTE)lpbi);
GlobalFreePtr(lpbi);
WaitCursorEnd();
return bSuccess;
}
///////////////////////////////////////////////////////////////////////
//从DIB数据块创建默认CDib对象
///////////////////////////////////////////////////////////////////////
bool CArdpsImg::Create(LPBYTE lpDIB)
{
if (lpDIB == NULL)
return false;
DWORD dwSize = DIBlockSize(lpDIB);
HDIB hDib = GlobalAlloc(GHND, dwSize);
// Check that DIB handle is valid
if (! hDib)
return false;
LPBYTE lpbi = (LPBYTE)GlobalLock(hDib);
if (! lpbi)
return false;
CopyMemory(lpbi, lpDIB, dwSize);
GlobalUnlock(hDib);
Destroy();
m_hDib = hDib;
LPBYTE ptmp = (LPBYTE) GlobalLock(m_hDib);
return UpdateInternal();
}
//*******************************************************************
// 功能:调用DIBToDIBSection函数,创建并更新DIB的DIBSECTION和DDB
//*******************************************************************
bool CArdpsImg::BuildBitmap()
{
if (m_pBitmap != NULL)
{
delete m_pBitmap;
m_pBitmap = NULL;
m_hBitmap = NULL;
}
m_hBitmap = DIBToDIBSection(m_hDib);
if (m_hBitmap == NULL)
return false;
m_pBitmap = new CBitmap;
m_pBitmap->Attach(m_hBitmap);
return true;
}
//*******************************************************************
//该函数调用CreateDIBPalette函数,创建并更新DIB调色板
//*******************************************************************
bool CArdpsImg::BuildPalette()
{
if (m_pPalette != NULL)
{
delete m_pPalette;
m_pPalette = NULL;
}
HPALETTE hPalette = CreateDIBPalette(m_hDib);
if (hPalette == NULL)
return false;
m_pPalette = new CPalette;
m_pPalette->Attach(hPalette);
return true;
}
//*******************************************************************
//UpdateInternal function 更新CDib对象所对应的调色板、DIBSECTION、DDB对象
//调用BuildPlaette 和BuildBitmap函数,重建CDib对象的,m_pPalette、m_hBitmap
//和m_pBitmap 成员数据
bool CArdpsImg::UpdateInternal()
{
BuildPalette();
return BuildBitmap();
}
void CArdpsImg::Destroy()
{
if (m_hDib != NULL)
{
DestroyDIB(m_hDib);
m_hDib = NULL;
}
if( m_hNewDib != NULL )
{
DestroyDIB(m_hNewDib);
m_hNewDib = NULL;
}
}
///////////////////////////////////////////////////////////////////////
//从DIB数据块创建CDib对象
///////////////////////////////////////////////////////////////////////
bool CArdpsImg::Create(LPBYTE lpDIB, WORD wBitCount) // bits/pixel
{
if (lpDIB == NULL)
return false;
if (! Create(lpDIB))
return false;
WORD wBits = ((LPBITMAPINFOHEADER)lpDIB)->biBitCount;
if (wBitCount == wBits)
return true;
HDIB hNewDib = ConvertDIBFormat(m_hDib, wBitCount, NULL);
if (! hNewDib)
return false;
Destroy();
m_hDib = hNewDib;
return UpdateInternal();
}
CPalette* CArdpsImg::GetPalette()
{
return m_pPalette;
}
bool CArdpsImg::Write(CFile *pFile)
{
WaitCursorBegin();
BITMAPFILEHEADER bmfHdr; // Header for Bitmap file
LPBITMAPINFOHEADER lpBI; // Pointer to DIB info structure
DWORD dwDIBSize;
// Get a pointer to the DIB memory, the first of which contains
// a BITMAPINFO structure
lpBI = (LPBITMAPINFOHEADER)GlobalLock(m_hDib);
if (!lpBI)
{
GlobalUnlock(m_hDib);
WaitCursorEnd();
return false;
}
// Check to see if we're dealing with an OS/2 DIB. If so, don't
// save it because our functions aren't written to deal with these
// DIBs.
if (lpBI->biSize != sizeof(BITMAPINFOHEADER))
{
GlobalUnlock(m_hDib);
WaitCursorEnd();
return false;
}
// Fill in the fields of the file header
// Fill in file type (first 2 bytes must be "BM" for a bitmap)
bmfHdr.bfType = DIB_HEADER_MARKER; // "BM"
// Calculating the size of the DIB is a bit tricky (if we want to
// do it right). The easiest way to do this is to call GlobalSize()
// on our global handle, but since the size of our global memory may have
// been padded a few bytes, we may end up writing out a few too
// many bytes to the file (which may cause problems with some apps,
// like HC 3.0).
//
// So, instead let's calculate the size manually.
//
// To do this, find size of header plus size of color table. Since the
// first DWORD in both BITMAPINFOHEADER and BITMAPCOREHEADER conains
// the size of the structure, let's use this.
// Partial Calculation
dwDIBSize = *(LPDWORD)lpBI + PaletteSize((LPBYTE)lpBI);
// Now calculate the size of the image
// It's an RLE bitmap, we can't calculate size, so trust the biSizeImage
// field
if ((lpBI->biCompression == BI_RLE8) || (lpBI->biCompression == BI_RLE4))
dwDIBSize += lpBI->biSizeImage;
else
{
DWORD dwBmBitsSize; // Size of Bitmap Bits only
// It's not RLE, so size is Width (DWORD aligned) * Height
dwBmBitsSize = MYWIDTHBYTES((lpBI->biWidth)*((DWORD)lpBI->biBitCount)) *
lpBI->biHeight;
dwDIBSize += dwBmBitsSize;
// Now, since we have calculated the correct size, why don't we
// fill in the biSizeImage field (this will fix any .BMP files which
// have this field incorrect).
lpBI->biSizeImage = dwBmBitsSize;
}
// Calculate the file size by adding the DIB size to sizeof(BITMAPFILEHEADER)
bmfHdr.bfSize = dwDIBSize + sizeof(BITMAPFILEHEADER);
bmfHdr.bfReserved1 = 0;
bmfHdr.bfReserved2 = 0;
// Now, calculate the offset the actual bitmap bits will be in
// the file -- It's the Bitmap file header plus the DIB header,
// plus the size of the color table.
bmfHdr.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + lpBI->biSize +
PaletteSize((LPBYTE)lpBI);
TRY
{
// Write the file header
pFile->Write(&bmfHdr, sizeof(BITMAPFILEHEADER));
// write DIB buffer
pFile->Write(lpBI, dwDIBSize);
}
CATCH (CException, e)
{
GlobalUnlock(m_hDib);
WaitCursorEnd();
return false;
}
END_CATCH
GlobalUnlock(m_hDib);
WaitCursorEnd();
return true;
}
bool CArdpsImg::IsEmpty()
{
if (m_hDib == NULL)
return true;
if (! GlobalLock(m_hDib))
return true;
GlobalUnlock(m_hDib);
return false;
}
bool CArdpsImg::Display(CDC * pDC, int x, int y, DWORD dwRop)
{
CDC MemDC;
MemDC.CreateCompatibleDC(pDC);
CBitmap* pOldBmp = MemDC.SelectObject(m_pBitmap);
CPalette* pOldPal = pDC->SelectPalette(m_pPalette, true);
pDC->RealizePalette();
bool bSuccess = pDC->BitBlt(x, y,
GetWidth(), GetHeight(),
&MemDC,
0, 0,
dwRop);
MemDC.SelectObject(pOldBmp);
pDC->SelectPalette(pOldPal, true);
return bSuccess;
}
WORD CArdpsImg::GetBitCount()
{
LPBITMAPINFOHEADER lpBI = (LPBITMAPINFOHEADER)GlobalLock(m_hDib);
if (!lpBI)
{
GlobalUnlock(m_hDib);
return 0;
}
WORD wBitCount = lpBI->biBitCount;
GlobalUnlock(m_hDib);
return wBitCount;
}
LONG CArdpsImg::GetWidth()
{
// get DIB buffer pointer
LPBYTE lpDIB = (LPBYTE)GlobalLock(m_hDib);
if (! lpDIB)
{
GlobalUnlock(m_hDib);
return 0;
}
LONG lWidth = (LONG)DIBWidth(lpDIB);
GlobalUnlock(m_hDib);
return lWidth;
}
LONG CArdpsImg::GetHeight()
{
// get DIB buffer pointer
LPBYTE lpDIB = (LPBYTE)GlobalLock(m_hDib);
if (! lpDIB)
{
GlobalUnlock(m_hDib);
return 0;
}
LONG lHeight = (LONG)DIBHeight(lpDIB);
GlobalUnlock(m_hDib);
return lHeight;
}
LONG CArdpsImg::GetWidthBytes()
{
return MYWIDTHBYTES((GetWidth())*((DWORD)GetBitCount()));
//return WIDTHBYTES((GetWidth())*((int)GetBitCount()));
}
LPBYTE CArdpsImg::GetBitsPtr()
{
LPBYTE lpDIB = (LPBYTE)GlobalLock(m_hDib);
if (! lpDIB)
{
GlobalUnlock(m_hDib);
return NULL;
}
LPBYTE lpData = FindDIBBits(lpDIB);
GlobalUnlock(m_hDib);
return lpData;
}
HANDLE CArdpsImg::GetHandle()
{
return m_hDib;
}
WORD CArdpsImg::GetColorNumber()
{
LPBYTE lpBI = (LPBYTE)GlobalLock(m_hDib);
if (! lpBI)
{
GlobalUnlock(m_hDib);
return 0;
}
WORD wColors = DIBNumColors(lpBI);
GlobalUnlock(m_hDib);
return wColors;
}
WORD CArdpsImg::GetPaletteSize()
{
LPBYTE lpBI = (LPBYTE)GlobalLock(m_hDib);
if (! lpBI)
{
GlobalUnlock(m_hDib);
return 0;
}
WORD wPalSize = PaletteSize(lpBI);
GlobalUnlock(m_hDib);
return wPalSize;
}
bool CArdpsImg::Attach(HDIB hDib)
{
if (hDib == NULL)
return false;
Destroy();
m_hDib = hDib;
return UpdateInternal();
}
bool CArdpsImg::ConvertFormat(WORD wBitCount)
{
if (IsEmpty())
return false;
if (GetBitCount() == wBitCount)
return true;
HDIB hNewDib = ConvertDIBFormat(m_hDib, wBitCount, NULL);
if (! hNewDib)
return false;
Destroy();
m_hDib = hNewDib;
return UpdateInternal();
}
/*
功能:加载其他图像格式,支持jpg、tiff格式
输入:
szImgFileName:文件名;
输出:
bBmp:加载成功,转换成DIB句柄
*/
HANDLE CArdpsImg::LoadNonDibHandle(BOOL *bBmp, char* szImgFileName)
{
*bBmp = FALSE;
char drive[_MAX_DRIVE];
char dir[_MAX_DIR];
char fname[_MAX_FNAME];
char ext[_MAX_EXT];
char szName[256];
typedef HANDLE (WINAPI * PGETDIBPROC)(HWND, char *, HANDLE);
PGETDIBPROC lpFun;
HANDLE hDib;
HINSTANCE hConvertLib = LoadLibrary("Convert.dll");
ASSERT(hConvertLib != NULL);
strcpy(szName, szImgFileName);
_splitpath(szName, drive, dir, fname, ext);
strcpy(szName, ext);
strlwr(szName);
if(strcmp(szName,".tif") == 0 || strcmp(szName, ".tiff") == 0)
{
//lpFun = (PGETDIBPROC)GetProcAddress(hConvertLib, "Tiff2HDIB");
/*hDib = LoadTiff(szImgFileName);*/
hDib = ReadBinTiff(szImgFileName);
return hDib;
}
else if(strcmp(szName,".jpg") == 0 || strcmp(szName,".jpeg") == 0 || strcmp(szName,".jpe") == 0 )
{
lpFun = (PGETDIBPROC)GetProcAddress(hConvertLib, "Jpg2HDIB");
}
else
{
if(hConvertLib)
{
FreeLibrary(hConvertLib);
}
*bBmp = TRUE;
return NULL;
}
ASSERT(lpFun != NULL);
freopen("nul", "w", stdout);
hDib = (*lpFun) ( NULL, szImgFileName, NULL);
freopen("con", "w", stdout);
if(hConvertLib)
{
FreeLibrary(hConvertLib);
}
return hDib;
}
/*
功能:BMP转换为其他图像格式
输入:
hDib:当前图像句柄;
strFileName:文件名;
nDestFileExtType:在ImgConv.h中定义
输出:
true:存储成功
*/
bool CArdpsImg::SaveNonDIB(HDIB hDib, CString strFileName, ImageType nDestFileExtType)
{
HMODULE hDll = LoadLibrary("ImgConv.dll");
if (hDll == NULL)
{
return false;
}
PFN_ImageConvert ImageConvert = (PFN_ImageConvert)GetProcAddress(hDll, "ImageConvert");
PFN_ImageDelete ImageDelete = (PFN_ImageDelete)GetProcAddress(hDll, "ImageDelete");
if (ImageConvert == NULL || ImageDelete == NULL)
{
FreeLibrary(hDll);
return false;
}
LPBITMAPINFOHEADER lpBI = (LPBITMAPINFOHEADER)GlobalLock(m_hDib);
bool bSave = false;
BITMAPFILEHEADER bmfHdr;
bool bInit = InitDIBFileHead(lpBI, &bmfHdr);
if( !bInit )
{
GlobalUnlock(m_hDib);
FreeLibrary(hDll);
return false;
}
unsigned char *pbSrc = new unsigned char [bmfHdr.bfSize];
if( !pbSrc )
{
GlobalUnlock(m_hDib);
FreeLibrary(hDll);
return false;
}
memcpy(pbSrc, &bmfHdr, sizeof(BITMAPFILEHEADER));
memcpy(pbSrc + sizeof(BITMAPFILEHEADER), lpBI, lpBI->biSizeImage * sizeof(unsigned char));
unsigned char * pDestData = NULL;
int nDestDataLen = 0;
bool bSuccess = false;
bSuccess = ImageConvert(pbSrc, bmfHdr.bfSize , imgBMP, &pDestData, &nDestDataLen, nDestFileExtType);
if( bSuccess )
{
FILE * pFile = fopen(strFileName, "wb");
if (pFile != NULL)
{
fwrite(pDestData, sizeof(unsigned char), nDestDataLen, pFile);
fclose(pFile);
ImageDelete(&pDestData);
bSave = true;
}
}
if (pbSrc)
{
delete []pbSrc;
pbSrc = NULL;
}
FreeLibrary(hDll);
GlobalUnlock(m_hDib);
return bSave;
}
bool CArdpsImg::InitDIBFileHead(LPBITMAPINFOHEADER lpBI, BITMAPFILEHEADER *lpbmfHdr )
{
if( !lpBI || !lpbmfHdr )
return false;
//BITMAPFILEHEADER bmfHdr;
lpbmfHdr->bfType = DIB_HEADER_MARKER; // "BM"
DWORD dwDIBSize = *(LPDWORD)lpBI + PaletteSize((LPBYTE)lpBI);
if ((lpBI->biCompression == BI_RLE8) || (lpBI->biCompression == BI_RLE4))
dwDIBSize += lpBI->biSizeImage;
else
{
DWORD dwBmBitsSize; // Size of Bitmap Bits only
// It's not RLE, so size is Width (DWORD aligned) * Height
dwBmBitsSize = MYWIDTHBYTES((lpBI->biWidth)*((DWORD)lpBI->biBitCount)) *
lpBI->biHeight;
dwDIBSize += dwBmBitsSize;
// Now, since we have calculated the correct size, why don't we
// fill in the biSizeImage field (this will fix any .BMP files which
// have this field incorrect).
lpBI->biSizeImage = dwBmBitsSize;
}
lpbmfHdr->bfSize = dwDIBSize + sizeof(BITMAPFILEHEADER);
lpbmfHdr->bfReserved1 = 0;
lpbmfHdr->bfReserved2 = 0;
lpbmfHdr->bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + lpBI->biSize + PaletteSize((LPBYTE)lpBI);
return true;
}
ImageType CArdpsImg::GetFileExtType(CString strExt)
{
if (strExt. CompareNoCase ("bmp") == 0 || strExt.CompareNoCase("dib") == 0 )
{
return imgBMP;
}
else if (strExt.CompareNoCase("gif") == 0 )
{
return imgGIF;
}
else if (strExt.CompareNoCase("jpg") == 0 )
{
return imgJPG;
}
else if (strExt.CompareNoCase("jpeg") == 0 || strExt.CompareNoCase("jpe") == 0 )
{
return imgJPEG;
}
else if (strExt.CompareNoCase("png") == 0 )
{
return imgPNG;
}
else if (strExt.CompareNoCase("tiff") || strExt.CompareNoCase("tif"))
{
return imgTIFF;
}
else
{
return imgBMP;
}
}
/*
功能:转换为灰度图像
输入:
nMethod:二值化方法;默认为0,加权平均方法;1为最大值;
uiGWeight,uiGWeight,uiBWeight:红、绿、蓝色分量
输出:
true:灰度化成功
*/
bool CArdpsImg::ConvertGray(int nMethod, UINT uiRWeight /* = 114 */, UINT uiGWeight /* = 587 */, UINT uiBWeight /* = 229 */)
{
LPBITMAPINFOHEADER lpDIBHdr = (LPBITMAPINFOHEADER)GlobalLock(m_hDib);
//for color image
LONG nImgHei = GetHeight();
LONG nImgWid = GetWidth();
LONG nOriBytesPerLine = GetWidthBytes();
int nBitCnt = GetBitCount();
if( nBitCnt < 24 )
{
GlobalUnlock(m_hDib);
return false;
}
//for gray image
LONG nGrayBytesPerLine = MYWIDTHBYTES( nImgWid << 3 );
LONG nGrayImgSize = nGrayBytesPerLine * nImgHei;
LONG nFileSize = nGrayImgSize + lpDIBHdr->biSize + 256 * sizeof(RGBQUAD);
//allocate memory for gray image
LPBYTE lpNewDIB = new BYTE[nFileSize];
if( !lpNewDIB )
{
GlobalUnlock(m_hDib);
return false;
}
memset(lpNewDIB, 0, nFileSize*sizeof(BYTE));
LPBITMAPINFOHEADER lpNewDIBHdr = (LPBITMAPINFOHEADER)lpNewDIB;
memcpy(lpNewDIBHdr, lpDIBHdr, sizeof(BITMAPINFOHEADER));
GlobalUnlock(m_hDib);
lpNewDIBHdr->biBitCount = 8;
lpNewDIBHdr->biCompression = BI_RGB;
lpNewDIBHdr->biSizeImage = nGrayImgSize;
lpNewDIBHdr->biClrUsed = 256;
//create RGBQUARD
RGBQUAD *pNewRGBQuad = (RGBQUAD*)(lpNewDIB +sizeof(BITMAPINFOHEADER));
memset(pNewRGBQuad, 0, 256*sizeof(RGBQUAD));
for( int i = 0; i < 256; ++i )
{
pNewRGBQuad->rgbBlue = pNewRGBQuad->rgbRed =
pNewRGBQuad->rgbGreen = i;
pNewRGBQuad++;
}
LPBYTE lpDIB = (LPBYTE)GlobalLock(m_hDib);
LPBYTE lpImg = FindDIBBits(lpDIB);
LPBYTE lpNewImg = lpNewDIB + sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD);
LPBYTE lpOritmp = lpImg;
LPBYTE lpNewtmp = lpNewImg;
int j, k, m, n, nStep = nBitCnt >> 3;
switch (nMethod)
{
case 0:
for( j = 0, m = 0, n = 0; j < nImgHei; ++j , m += nOriBytesPerLine, n += nGrayBytesPerLine )
{
lpNewtmp = lpNewImg + n;
lpOritmp = lpImg + m;
for( k = 0; k < nImgWid; ++k, lpNewtmp ++ )
{
*lpNewtmp = BYTE(( (*lpOritmp) *uiRWeight +
*(lpOritmp + 1) * uiGWeight + *(lpOritmp + 2) * uiBWeight )/1000);
lpOritmp += nStep;
}
}
break;
case 1:
default:
for( j = 0, m = 0, n = 0; j < nImgHei; ++j , m += nOriBytesPerLine, n += nGrayBytesPerLine )
{
lpNewtmp = lpNewImg + n;
lpOritmp = lpImg + m;
for( k = 0; k < nImgWid; ++k, lpNewtmp ++ )
{
*lpNewtmp = BYTE( max(max ( (*lpOritmp), *(lpOritmp + 1) ), *(lpOritmp + 2) ));
lpOritmp += nStep;
}
}
break;
}
GlobalUnlock(m_hDib);
bool bCrate = Create(lpNewDIB);
if( lpNewDIB )
{
delete []lpNewDIB;
lpNewDIB = NULL;
}
return true;
}
/*
功能:对灰度图像进行二值化
输入:
nMethod:二值化方法;默认为0,OTSU方法;1为均值;2:为给定阈值方法
nTh:二值化阈值
输出:
true:二值化成功
*/
bool CArdpsImg::ConvertBinary(int nMethod /* = 0 */, int nTh /* = 0 */)
{
//for image
int nBitCnt = GetBitCount();
//for gray image
LONG nGrayBytesPerLine = GetWidthBytes();
if( nBitCnt > 8 )
{
bool bGray = ConvertGray(0);
if(!bGray)
{
return false;
}
//lpDIBHdr = (LPBITMAPINFOHEADER)GlobalLock(m_hDib);
}
else if( nBitCnt == 1)
{
return true;
}
LPBITMAPINFOHEADER lpDIBHdr = (LPBITMAPINFOHEADER)GlobalLock(m_hDib);
LONG nImgHei = GetHeight();
LONG nImgWid = GetWidth();
//for binary image
LONG nBinaryBytesPerLine = MYWIDTHBYTES( nImgWid );
LONG nBinaryImgSize = nBinaryBytesPerLine * nImgHei;
LONG nFileSize = nBinaryImgSize + lpDIBHdr->biSize + 2 * sizeof(RGBQUAD);
//allocate memory for binary image
LPBYTE lpNewDIB = new BYTE[nFileSize];
if( !lpNewDIB )
{
GlobalUnlock(m_hDib);
return false;
}
memset(lpNewDIB, 0, nFileSize*sizeof(BYTE));
LPBITMAPINFOHEADER lpNewDIBHdr = (LPBITMAPINFOHEADER)lpNewDIB;
memcpy(lpNewDIBHdr, lpDIBHdr, sizeof(BITMAPINFOHEADER));
GlobalUnlock(m_hDib);
lpNewDIBHdr->biBitCount = 1;
lpNewDIBHdr->biCompression = 0;
lpNewDIBHdr->biSizeImage = nBinaryImgSize;
lpNewDIBHdr->biClrUsed = 2;
lpNewDIBHdr->biXPelsPerMeter = 0;
lpNewDIBHdr->biYPelsPerMeter = 0;
//create RGBQUARD
RGBQUAD *pNewRGBQuad = (RGBQUAD*)(lpNewDIB +sizeof(BITMAPINFOHEADER));
pNewRGBQuad->rgbRed = pNewRGBQuad->rgbGreen = pNewRGBQuad->rgbBlue
= 0;
pNewRGBQuad->rgbReserved = 0;
pNewRGBQuad++;
pNewRGBQuad->rgbRed = pNewRGBQuad->rgbGreen = pNewRGBQuad->rgbBlue
= 255;
pNewRGBQuad->rgbReserved = 0;
LPBYTE lpDIB = (LPBYTE)GlobalLock(m_hDib);
LPBYTE lpImg = FindDIBBits(lpDIB);
LPBYTE lpNewImg = lpNewDIB + sizeof(BITMAPINFOHEADER) + 2 * sizeof(RGBQUAD);
LPBYTE lpOritmp = lpImg;
LPBYTE lpNewtmp = lpNewImg;
int nStep = nBitCnt >> 3;
bool bResult = false;
switch (nMethod)
{
case 1:
nTh = 0;
bResult = IntensityMean( lpImg, nImgWid, nImgHei, nTh );
break;
case 2:
bResult = true;
break;
case 0:
default:
nTh = 0;
OtsuTh(nImgWid, nImgHei, lpImg, nTh);
bResult = true;
break;
}
if( bResult )
bResult = ThreshImage(lpImg, lpNewImg, nImgWid, nImgHei, nTh);
GlobalUnlock(m_hDib);
bool bCrate = Create(lpNewDIB);
if (lpNewDIB)
{
delete []lpNewDIB;
lpNewDIB = NULL;
}
return bCrate;
}
/*
功能:利用Otsu方法计算二值化的阈值
输入:
lpBits:灰度图像内存指针
nW:图像宽度
nH:图像高度
输出:
Th:图像灰度均值
*/
void CArdpsImg:: OtsuTh( DWORD nW, DWORD nH, BYTE *lpBits, int &Th)
{
UINT i;
float bmax;
float counter1,counter2;
float mean1,mean2;
int TH, threshold, k, deta;
float sum1,sum2;
int buf[256];
memset(buf, 0, 256 * sizeof(int));
if( !GetGrayHist(lpBits, nW, nH, buf) )
return;
for ( i = 0; i < 256; i ++)
{
bufi[i] = i * buf[i];
}
deta = 10; //计算阈值的步长,以加快求解速度。
counter1 = 0;
for ( TH = 0; TH < 256; TH += deta )
{
counter1 = counter2=0;
sum1 = sum2=0.0;
for( k = 0; k <= TH; k++ )
{
counter1 += buf[k];
sum1 += bufi[k];
}
for( k = TH + 1; k < 256; k++ )
{
counter2 += buf[k];
sum2 += bufi[k];
}
if ( counter1>0 ) mean1= sum1/counter1;
else mean1=0;
if ( counter2>0 ) mean2= sum2/counter2;
else mean2=0;
varience[TH]=counter1*counter2*(mean1-mean2)*(mean1-mean2);
}
bmax=varience[0]; threshold=0;
for ( TH=0; TH<256; TH += deta )
{
if( bmax<varience[TH] )
{
bmax=varience[TH];
threshold=TH;
}
}
Th=threshold;
}
/*
功能:计算图像的灰度均值
输入:
pbGray:灰度图像内存指针
nImgWid:图像宽度
nImgHei:图像高度
输出:
nIntenMean:图像灰度均值
*/
bool CArdpsImg::IntensityMean(const BYTE *pbGray, const int nImgWid, const int nImgHei, int &nIntenMean )
{
if( pbGray == NULL || nImgHei <= 0 || nImgWid <= 0 )
return false;
int nSum = 0;
nIntenMean = 0;
for( int i = 0; i < nImgHei * nImgWid; i++ )
{
nSum += *pbGray ++;
}
nIntenMean = BYTE(nSum /((nImgHei * nImgWid) + 1));
return true;
}
bool CArdpsImg::ThreshImage(const BYTE *pbImg, BYTE *pbBinary, const int nImgWid, const int nImgHei, const int nTh )
{
if( pbImg == NULL || pbBinary== NULL )
return false;
LONG nGrayPerLine = MYWIDTHBYTES(nImgWid << 3);
LONG nBinaryPerLine = MYWIDTHBYTES(nImgWid);
const BYTE *pbIn = pbImg;
BYTE *pbOut = pbBinary;
BYTE tmp = 0;
for( int i = 0, m = 0, n = 0; i < nImgHei; ++i )
{
pbIn = pbImg + m;
pbOut = pbBinary + n;
for(int j = 0; j < nImgWid/8; ++j )
{
tmp = 0;
if( *pbIn > nTh )
tmp = tmp | 128;
++pbIn;
if( *pbIn > nTh )
tmp = tmp | 64;
++pbIn;
if( *pbIn > nTh )
tmp = tmp | 32;
++pbIn;
if( *pbIn > nTh )
tmp = tmp | 16;
++pbIn;
if( *pbIn > nTh )
tmp = tmp | 8;
++pbIn;
if( *pbIn > nTh )
tmp = tmp | 4;
++pbIn;
if( *pbIn > nTh )
tmp = tmp | 2;
++pbIn;
if( *pbIn > nTh )
tmp = tmp | 1;
++pbIn;
*pbOut ++ = tmp;
}
tmp = 0;
for( int k = 0; k < nImgWid % 8; k++, pbIn++ )
{
if( *pbIn > nTh )
{
tmp += 1;
}
tmp = tmp << 1;
}
*pbOut = tmp << (8 - nImgWid % 8 - 1);
m += nGrayPerLine;
n += nBinaryPerLine;
}
return true;
}
/******************************************************************
功能:灰度图像的均衡化,使得像素在灰度阶上尽量均匀
输入:
当前图像的内存句柄
输出:
灰度成功返回true
******************************************************************/
bool CArdpsImg::GrayEqual()
{
if(IsEmpty())
return false;
if( !GrayEqualize(m_hDib))
return false;
return UpdateInternal();
}
/****************************************************************************
功能:对灰度图像进行拉伸
输入:
nMethod:灰度图像内存指针。
(x1,y1):拉伸曲线的第一点坐标
(x2,y2):拉伸曲线的第二点坐标
*(255,255)
*
* (x2,y2)
*
*
*
*(x1,y1)
*
*(0,0)
nMethod = 0:根据直方图自动计算第一点和第二点坐标,阈值取累积直方图的10%~90%。
nMethod = 1:根据输入的坐标进行计算
输出:
操作成功返回True。
**********************************************************************************/
bool CArdpsImg::GrayStretch(int nMethod, BYTE x1 = 0 , BYTE y1 = 0 , BYTE x2 = 255, BYTE y2 = 255 )
{
if(IsEmpty())
return false;
if(!GrayStretchDIB(nMethod, m_hDib, x1, y1, x2, y2) )
return false;
return UpdateInternal();
}
/*******************************************************************
功能:去除矩形区域二值化图像的污点
输入:
nMethod = 0:去污,选中区域如果为白色占主要部分则变成黑色
否则相反。
nMethod = 1 :磨白,把选中的区域变成白色
nMethod = 2:填充,把选中的区域变成黑色
rct:选中的处理区域
输出:
去除成功
*******************************************************************/
bool CArdpsImg::EliminateDirt(int nMethod, const CRect rct)
{
if ( rct.IsRectEmpty() || IsEmpty() )
return false;
// Convert the physical coordinate into imaging coordinate
if( GetBitCount() > 1 )
return false;
if(!EliminateDirtDIB(nMethod, m_hDib, rct) )
return false;
return UpdateInternal();
}
/*******************************************************************
功能:去除圆形区域二值化图像的污点
输入:
nMethod = 0:去污,选中区域如果为白色占主要部分则变成黑色
否则相反。
nMethod = 1 :磨白,把选中的区域变成白色
nMethod = 2:填充,把选中的区域变成黑色
rct:选中的处理区域
输出:
去除成功
*******************************************************************/
bool CArdpsImg::EliminateDirt(int nMethod, const int nCircleX, const int nCircleY, const int nRadius)
{
if( IsEmpty() || nCircleX < 0 || nCircleY < 0 || nRadius < 0 )
return false;
if( GetBitCount() > 1 )
return false;
if(!EliminateDirtDIB(nMethod, m_hDib, nCircleX, nCircleY, nRadius) )
return false;
return UpdateInternal();
}
/******************************************************************
功能:设置污点的大小
输入:
sz,污点大小,小于sz为污点
******************************************************************/
void CArdpsImg::SetDirtSize(CSize szMax, CSize szMin)
{
m_DirtSize = szMax;
m_minDirtSize = szMin;
}
/******************************************************************
功能:自动去除图像中的小于一定面积的污点
输入:
nMethod,去除0黑色污点,1去除白色污点
nMinArea,污点的最大面积,小于该污点的像素区域将被作为污点
输出:
去除成功返回true
******************************************************************/
bool CArdpsImg::AutoEliminateDirt(int nMethod, int nMinArea)
{
LPBYTE lpDIB = (LPBYTE)GlobalLock(m_hDib);
if( !lpDIB)
return false;
LPBYTE lpBinImg = FindDIBBits(lpDIB);
if( !lpBinImg )
{
GlobalUnlock(m_hDib);
return false;
}
bool bSuccess = true;
LONG nImgHei = GetHeight();
LONG nImgWid = GetWidth();
int nBitCnt = DIBBitCount(lpDIB);
if( nBitCnt != 1 )
{
GlobalUnlock(m_hDib);
return false;
}
LONG nBinBytesPerLine = MYWIDTHBYTES(nImgWid * nBitCnt);
//for gray image
LONG nGrayBytesPerLine = MYWIDTHBYTES( nImgWid << 3 );
LONG nGrayImgSize = nGrayBytesPerLine * nImgHei;
BYTE *pbGrayImg = new BYTE[nGrayImgSize];
if( !pbGrayImg )
{
GlobalUnlock(m_hDib);
return false;
}
bSuccess = ConvertBinary2Gray(lpBinImg, nImgWid, nImgHei, pbGrayImg );
//SaveTo8bit_BMP(pbGrayImg, nImgWid, nImgHei, "d:\\testgray.bmp", 8);
if( !bSuccess )
{
delete []pbGrayImg;
pbGrayImg = NULL;
GlobalUnlock(m_hDib);
return false;
}
Line *Li = new Line;
if( !Li )
{
delete []pbGrayImg;
pbGrayImg = NULL;
GlobalUnlock(m_hDib);
return false;
}
Li->StartY = 3;
Li->StartX = 3;
Li->EndX = nImgWid - 3;
Li->EndY = nImgHei - 3;
Li->cp = NULL;
BYTE bCur;
if( nMethod == 0 ) //黑色为背景
{
bCur = 0;
}
else
{
bCur = 255;
}
ExtractComponent(Li, pbGrayImg, nGrayBytesPerLine, bCur );
AnalysisComponent(Li, pbGrayImg, nGrayBytesPerLine, nMinArea, 255- bCur);
// SaveTo8bit_BMP(pbGrayImg, nImgWid, nImgHei, "d:\\testcom.bmp", 8);
ThreshImage(pbGrayImg, lpBinImg, nImgWid, nImgHei, 128);
if( pbGrayImg )
{
delete []pbGrayImg;
pbGrayImg = NULL;
}
if( Li )
{
delete Li;
Li = NULL;
}
GlobalUnlock(m_hDib);
return UpdateInternal();
}
bool CArdpsImg::AutoEliminateDirt(int nMethod, CRect *pRect, int *pFlag, const int nNum)
{
if( !pRect || !pFlag )
return false;
LPBYTE lpDIB = (LPBYTE)GlobalLock(m_hDib);
if( !lpDIB)
return false;
LPBYTE lpBinImg = FindDIBBits(lpDIB);
if( !lpBinImg )
{
GlobalUnlock(m_hDib);
return false;
}
bool bSuccess = true;
LONG nImgHei = GetHeight();
LONG nImgWid = GetWidth();
int nBitCnt = DIBBitCount(lpDIB);
if( nBitCnt != 1 )
{
GlobalUnlock(m_hDib);
return false;
}
LONG nBinBytesPerLine = MYWIDTHBYTES(nImgWid * nBitCnt);
//for gray image
LONG nGrayBytesPerLine = MYWIDTHBYTES( nImgWid << 3 );
LONG nGrayImgSize = nGrayBytesPerLine * nImgHei;
BYTE *pbGrayImg = new BYTE[nGrayImgSize];
if( !pbGrayImg )
{
GlobalUnlock(m_hDib);
return false;
}
bSuccess = ConvertBinary2Gray(lpBinImg, nImgWid, nImgHei, pbGrayImg );
if( !bSuccess )
{
delete []pbGrayImg;
pbGrayImg = NULL;
GlobalUnlock(m_hDib);
return false;
}
BYTE bCur;
if( nMethod == 0 ) //黑色为背景
{
bCur = 0;
}
else
{
bCur = 255;
}
CRect tmpRt;
for( int i = 0; i < nNum; i++ )
{
if (pFlag[i] == 1)
{
tmpRt.top = nImgHei - 1 - pRect[i].bottom;
tmpRt.bottom = nImgHei - 1 - pRect[i].top;
tmpRt.left = pRect[i].left;
tmpRt.right = pRect[i].right;
SetBinary(tmpRt, pbGrayImg, nGrayBytesPerLine, 255-bCur);
}
}
ThreshImage(pbGrayImg, lpBinImg, nImgWid, nImgHei, 128);
if( pbGrayImg )
{
delete []pbGrayImg;
pbGrayImg = NULL;
}
GlobalUnlock(m_hDib);
return UpdateInternal();
}
/******************************************************************
功能:以原有图像中心为原点,给定的角度旋转图像
输入:
iRotateAngle,指定旋转的度数,正值为向右旋转,反之向右旋转
输出:
旋转成功返回true
******************************************************************/
bool CArdpsImg::RotateImage(int iRotateAngle /* = 0 */)\
{
// 源图像的宽度和高度
LONG lWidth;
LONG lHeight;
// 旋转后图像的宽度和高度
LONG lNewWidth;
LONG lNewHeight;
// 图像每行的字节数
LONG lLineBytes;
// 旋转后图像的宽度(lNewWidth',必须是4的倍数)
LONG lNewLineBytes;
// 指向源图像的指针
LPBYTE lpDIBBits;
// 指向源象素的指针
LPBYTE lpSrc;
// 旋转后新DIB句柄
HDIB hDIB;
// 指向旋转图像对应象素的指针
LPBYTE lpDst;
// 指向旋转图像的指针
LPBYTE lpNewDIB;
LPBYTE lpNewDIBBits;
// 指向BITMAPINFO结构的指针(Win3.0)
LPBITMAPINFOHEADER lpbmi;
// 指向BITMAPCOREINFO结构的指针
LPBITMAPCOREHEADER lpbmc;
// 旋转角度(弧度)
float fRotateAngle;
// 旋转角度的正弦和余弦
float fSina, fCosa;
// 源图四个角的坐标(以图像中心为坐标系原点)
float fSrcX1,fSrcY1,fSrcX2,fSrcY2,fSrcX3,fSrcY3,fSrcX4,fSrcY4;
// 旋转后四个角的坐标(以图像中心为坐标系原点)
float fDstX1,fDstY1,fDstX2,fDstY2,fDstX3,fDstY3,fDstX4,fDstY4;
// 两个中间常量
float f1,f2;
LPBYTE lpDIB = (LPBYTE)GlobalLock(m_hDib);
// 找到源DIB图像象素起始位置
lpDIBBits = FindDIBBits(lpDIB);
// 获取图像的"宽度"(4的倍数)
lWidth = DIBWidth(lpDIB);
WORD dwBitCnt = DIBBitCount(lpDIB);
if (dwBitCnt != 8 && dwBitCnt != 24 && dwBitCnt != 1 )
{
GlobalUnlock(m_hDib);
return false;
}
// 获取图像的高度
lHeight = DIBHeight(lpDIB);
LPBYTE pBin2Gray = NULL;
int lBin2GrayLineBytes = MYWIDTHBYTES(lWidth * 8);
if( dwBitCnt == 1)
{
pBin2Gray = new BYTE[lBin2GrayLineBytes * lHeight];
if( !pBin2Gray )
{
GlobalUnlock(m_hDib);
return false;
}
memset(pBin2Gray, 0, lBin2GrayLineBytes * lHeight);
ConvertBinary2Gray(lpDIBBits, lWidth, lHeight, pBin2Gray);
lpDIBBits = pBin2Gray;
}
// 计算图像每行的字节数
lLineBytes = MYWIDTHBYTES(lWidth * dwBitCnt);
// 将旋转角度从度转换到弧度
fRotateAngle = (float) RADIAN(iRotateAngle);
// 计算旋转角度的正弦
fSina = (float) sin((double)fRotateAngle);
// 计算旋转角度的余弦
fCosa = (float) cos((double)fRotateAngle);
// 计算原图的四个角的坐标(以图像中心为坐标系原点)
fSrcX1 = (float) (- (lWidth - 1) / 2);
fSrcY1 = (float) ( (lHeight - 1) / 2);
fSrcX2 = (float) ( (lWidth - 1) / 2);
fSrcY2 = (float) ( (lHeight - 1) / 2);
fSrcX3 = (float) (- (lWidth - 1) / 2);
fSrcY3 = (float) (- (lHeight - 1) / 2);
fSrcX4 = (float) ( (lWidth - 1) / 2);
fSrcY4 = (float) (- (lHeight - 1) / 2);
// 计算新图四个角的坐标(以图像中心为坐标系原点)
fDstX1 = fCosa * fSrcX1 + fSina * fSrcY1 - 0.5;
fDstY1 = -fSina * fSrcX1 + fCosa * fSrcY1 - 0.5;
fDstX2 = fCosa * fSrcX2 + fSina * fSrcY2 - 0.5;
fDstY2 = -fSina * fSrcX2 + fCosa * fSrcY2 + 0.5;
fDstX3 = fCosa * fSrcX3 + fSina * fSrcY3 + 0.5;
fDstY3 = -fSina * fSrcX3 + fCosa * fSrcY3 - 0.5;
fDstX4 = fCosa * fSrcX4 + fSina * fSrcY4 + 0.5;
fDstY4 = -fSina * fSrcX4 + fCosa * fSrcY4 + 0.5;
// 计算旋转后的图像实际宽度
lNewWidth = (LONG) ( max( fabs(fDstX4 - fDstX1), fabs(fDstX3 - fDstX2) ) + 0.5);
// 计算旋转后的图像高度
lNewHeight = (LONG) ( max( fabs(fDstY4 - fDstY1), fabs(fDstY3 - fDstY2) ) + 0.5);
if( iRotateAngle == 90 || iRotateAngle == 270 )
{
lNewHeight = lWidth;
lNewWidth = lHeight;
}
else if( iRotateAngle == 0 || iRotateAngle == 360 || iRotateAngle == 180 )
{
lNewHeight = lHeight;
lNewWidth = lWidth;
}
lNewLineBytes = MYWIDTHBYTES(lNewWidth * dwBitCnt);
f1 = (float) (-0.5 * (lNewWidth - 1) * fCosa - 0.5 * (lNewHeight - 1) * fSina
+ 0.5 * (lWidth - 1));
f2 = (float) ( 0.5 * (lNewWidth - 1) * fSina - 0.5 * (lNewHeight - 1) * fCosa
+ 0.5 * (lHeight - 1));
// 分配内存,以保存新DIB
hDIB = (HDIB) ::GlobalAlloc(GHND, lNewLineBytes * lNewHeight + *(LPDWORD)lpDIB + ::PaletteSize(lpDIB));
// 判断是否内存分配失败
if (hDIB == NULL)
{
GlobalUnlock(m_hDib);
return false;
}
// 锁定内存
lpNewDIB = (LPBYTE)GlobalLock((HGLOBAL) hDIB);
// 复制DIB信息头和调色板
memcpy(lpNewDIB, lpDIB, *(LPDWORD)lpDIB + PaletteSize(lpDIB));
// 找到新DIB象素起始位置
lpNewDIBBits = FindDIBBits(lpNewDIB);
// 获取指针
lpbmi = (LPBITMAPINFOHEADER)lpNewDIB;
lpbmc = (LPBITMAPCOREHEADER)lpNewDIB;
// 更新DIB中图像的高度和宽度
if (IS_WIN30_DIB(lpNewDIB))
{
// 对于Windows 3.0 DIB
lpbmi->biWidth = lNewWidth;
lpbmi->biHeight = lNewHeight;
}
else
{
// 对于其它格式的DIB
lpbmc->bcWidth = (unsigned short) lNewWidth;
lpbmc->bcHeight = (unsigned short) lNewHeight;
}
LPBYTE pNewGray = NULL;
if( dwBitCnt == 1 )
{
lNewLineBytes = MYWIDTHBYTES(lNewWidth * 8);
lLineBytes = lBin2GrayLineBytes;
pNewGray = new BYTE[lNewLineBytes * lNewHeight];
if( !pNewGray )
{
GlobalUnlock(m_hDib);
if( pBin2Gray )
delete []pBin2Gray;
pBin2Gray = NULL;
GlobalUnlock(hDIB);
GlobalFree(hDIB);
hDIB = NULL;
return false;
}
lpNewDIBBits = pNewGray;
}
LONG i, j, m, i0, j0;
for(i = 0, m = lNewLineBytes*(lNewHeight-1); i < lNewHeight; i++, m -= lNewLineBytes )
{
lpDst = lpNewDIBBits + m;
for(j = 0; j < lNewWidth; j++)
{
// 计算该象素在源DIB中的坐标
i0 = (LONG) (-((float) j) * fSina + ((float) i) * fCosa + f2 + 0.5);
j0 = (LONG) ( ((float) j) * fCosa + ((float) i) * fSina + f1 + 0.5);
// 判断是否在源图范围内
if( (j0 >= 0) && (j0 < lWidth) && (i0 >= 0) && (i0 < lHeight))
{
// 指向源DIB第i0行,第j0个象素的指针
if( dwBitCnt == 8 || dwBitCnt == 1 )
{
lpSrc = lpDIBBits + lLineBytes *( lHeight - 1 -i0 )+ j0;
// 复制象素
*lpDst ++= *lpSrc;
}
else if( dwBitCnt == 24 )
{
lpSrc = lpDIBBits + lLineBytes *( lHeight - 1 -i0 )+ j0 * 3;
*lpDst ++ = *lpSrc;
lpSrc++;
*lpDst ++ = *lpSrc;
lpSrc++;
*lpDst ++ = *lpSrc;
}
}
else
{
// 对于源图中没有的象素,直接赋值为255
if( dwBitCnt == 8 || dwBitCnt == 1)
{
* lpDst ++ = 255;
}
else if (dwBitCnt == 24)
{
*lpDst ++ = 255;
*lpDst ++ = 255;
*lpDst ++ = 255;
}
}
}
}
if( dwBitCnt == 1 )
{
lpNewDIBBits = FindDIBBits(lpNewDIB);
ThreshImage(pNewGray, lpNewDIBBits, lNewWidth,lNewHeight, 10);
if( pNewGray )
delete []pNewGray;
pNewGray = NULL;
if( pBin2Gray )
delete []pBin2Gray;
pBin2Gray = NULL;
}
GlobalUnlock(m_hDib);
GlobalFree(m_hDib);
m_hDib = hDIB;
return UpdateInternal();
}
/******************************************************************
功能:以原有灰度图像中心为原点,自动检测角度并旋转图像
倾斜角度范围-10——+10度
输入:
rtROI,给定的区域,用于检测文档的倾斜角度.输入区域为bottom = 0 或者right = 0,则设为图像区域
输出:
旋转成功返回true
******************************************************************/
bool CArdpsImg::AutoRotatelImage(RECT rtROI)
{
LPBYTE lpDIB = (LPBYTE)GlobalLock(m_hDib);
LONG lWidth = DIBWidth(lpDIB);
LONG lHeight = DIBHeight(lpDIB);
if( rtROI.bottom > lHeight || rtROI.right > lWidth )
{
GlobalUnlock(m_hDib);
return false;
}
if( rtROI.left < EDGE_STEP )
rtROI.left = EDGE_STEP;
if( rtROI.right >= lWidth - EDGE_STEP )
rtROI.right = lWidth - EDGE_STEP - 1;
if (rtROI.top < EDGE_STEP )
rtROI.top = EDGE_STEP;
if( rtROI.bottom >= lHeight - EDGE_STEP )
rtROI.bottom = lHeight - 1 - EDGE_STEP;
if( rtROI.bottom == 0 )
rtROI.bottom = lHeight-EDGE_STEP;
if(rtROI.right == 0)
rtROI.right = lWidth - EDGE_STEP;
LPBYTE lpDIBBits = FindDIBBits(lpDIB);
WORD dwBitCnt = DIBBitCount(lpDIB);
if( dwBitCnt != 8 )
{
GlobalUnlock(m_hDib);
return false;
}
LONG lLineBytes = MYWIDTHBYTES(lWidth * dwBitCnt);
BYTE * pbOutImage = new BYTE[lLineBytes * lHeight];
if( !pbOutImage )
{
GlobalUnlock(m_hDib);
return false;
}
memset(pbOutImage, 0, lLineBytes * lHeight* sizeof(BYTE));
BYTE *pbTmp = new BYTE[lLineBytes * lHeight];
if( !pbTmp )
{
GlobalUnlock(m_hDib);
delete []pbOutImage;
pbOutImage = NULL;
}
memset(pbTmp, 0, lLineBytes * lHeight* sizeof(BYTE));
bool bSuccess = FindTopEdge(pbOutImage, lpDIBBits, rtROI, lLineBytes);
//SaveTo8bit_BMP(lpDIBBits, lWidth, lHeight, "edgegray.bmp", 8);
//SaveTo8bit_BMP(pbOutImage, lWidth, lHeight, "edge0.bmp", 8);
DeleteVtlSmallLine(pbOutImage, pbTmp, lLineBytes, lHeight, 5);
//SaveTo8bit_BMP(pbOutImage, lWidth, lHeight, "edge1.bmp", 8);
double dK;
if( bSuccess )
{
dK = DetectSkewAngle(pbOutImage, rtROI, lLineBytes);
bSuccess = RotateImage(dK);
}
if( pbOutImage )
{
delete []pbOutImage;
pbOutImage = NULL;
}
if( pbTmp )
{
delete []pbTmp;
pbTmp = NULL;
}
GlobalUnlock(m_hDib);
if( bSuccess )
return UpdateInternal();
else
return bSuccess;
}
/******************************************************************
功能:自动去除灰度图像的黑白边
输入:
输出:
去除成功返回true
******************************************************************/
bool CArdpsImg::CutFrame()
{
BYTE * pbOut = NULL;
bool bSuccess = false;
LPBITMAPINFOHEADER lpbmi = NULL;
LPBITMAPCOREHEADER lpbmc = NULL;
LPBYTE lpDIB = (LPBYTE)GlobalLock(m_hDib);
LONG lWidth = DIBWidth(lpDIB);
LONG lHeight = DIBHeight(lpDIB);
LPBYTE lpDIBBits = FindDIBBits(lpDIB);
WORD dwBitCnt = DIBBitCount(lpDIB);
if( dwBitCnt != 8 )
{
goto CleanUp;
}
RECT rect;
rect = SetRectValue(0, 0, 0, 0);
LONG lLineBytes = MYWIDTHBYTES(lWidth << 3);
LONG lImgBytes = lLineBytes * lHeight;
pbOut = new BYTE[lImgBytes];
if( !pbOut )
{
goto CleanUp;
}
memset(pbOut, 0, lImgBytes * sizeof(BYTE));
rect = SetRectValue(4, lWidth - 4, 4, lHeight - 4);
if (FindEdgeImage(pbOut, lpDIBBits, rect, lWidth) < 0)
{
goto CleanUp;
}
rect = GetEdgeImageBoundary(pbOut, lWidth, lHeight);
RECT rtPhy;
rtPhy = rect;
rtPhy.bottom = lHeight - 1 - rect.top;
rtPhy.top = lHeight - 1 - rect.bottom;
HDIB hDIB = CropDIB(m_hDib, &rtPhy);
if( hDIB == NULL )
goto CleanUp;
bSuccess = true;
CleanUp:
if( pbOut )
{
delete []pbOut;
pbOut = NULL;
}
GlobalUnlock(m_hDib);
GlobalFree(m_hDib);
m_hDib = hDIB;
if( bSuccess )
return UpdateInternal();
else
return bSuccess;
}
/******************************************************************
功能:将图像拆页为两幅图像
输入:
pt1,pt2:给定的拆分的线的任意两点坐标
pNewArd:返回CArdpsImg对象,拆分后的下、右半幅图像句柄存于该对象中
输出:
拆分成功返回true
******************************************************************/
bool CArdpsImg::SplitImage(POINT pt1, POINT pt2, CArdpsImg *pNewArd)
{
bool bSuccess = false;
if( pNewArd == NULL )
return bSuccess;
LPBYTE lpDIB = (LPBYTE)GlobalLock(m_hDib);
LONG lWidth = DIBWidth(lpDIB);
LONG lHeight = DIBHeight(lpDIB);
int nx, ny;
nx = abs(pt1.x - pt2.x) ;
ny = abs(pt1.y - pt2.y) >lHeight - 1 ? lHeight - 1 : abs(pt1.y - pt2.y) ;
RECT rtROI, rtROI2;
if( nx < ny )
{
nx = (pt1.x + pt2.x + 0.5)/2 > lWidth - 1 ? lWidth - 1 : (pt1.x + pt2.x + 0.5)/2; //垂直分割
rtROI = SetRectValue(0, nx -1, 0, lHeight - 1);
rtROI2 = SetRectValue(nx, lWidth -1, 0, lHeight - 1);
}
else
{
ny = (pt1.y + pt2.y + 0.5) / 2 > lHeight - 1 ? lHeight - 1 : (pt1.y + pt2.y + 0.5) / 2 ;
rtROI = SetRectValue(0, lWidth - 1, 0, ny - 1);
rtROI2 = SetRectValue(0, lWidth - 1, ny, lHeight - 1);
}
HDIB hDib1, hDib2;
hDib1 = CropDIB(m_hDib, &rtROI );
hDib2 = CropDIB(m_hDib, &rtROI2);
GlobalUnlock(m_hDib);
GlobalFree(m_hDib);
m_hDib = hDib1;
pNewArd->m_hDib = hDib2;
return true;
}
/******************************************************************
功能:将两幅图像合并为一幅图像
输入:
pSrcArd:输入的CArdpsImg对象,图像的句柄存于该对象中
nMethod:0:上下合并,Src位于合并后的下半幅;1:上下合并,Src位于合并后的上半幅
2:左右合并,Src位于合并后的右半幅;3:左右合并,Src位于合并后的左半幅
输出:
拆分成功返回true
******************************************************************/
bool CArdpsImg::MergeImage(CArdpsImg *pSrcArd, int nMethod /* = 0 */)
{
bool bSuccess = false;
if( pSrcArd == NULL )
return bSuccess;
//当前图像
LPBYTE lpDIB = (LPBYTE)GlobalLock(m_hDib);
LONG lWidth = DIBWidth(lpDIB);
LONG lHeight = DIBHeight(lpDIB);
WORD bitCnt = DIBBitCount(lpDIB);
LONG lBytePerLine = MYWIDTHBYTES(lWidth * bitCnt);
LPBYTE lpDIBBits = FindDIBBits(lpDIB);
//欲合并的图像
LPBYTE lpSrcDIB = (LPBYTE)GlobalLock(pSrcArd->m_hDib);
LONG lSrcWidth = DIBWidth(lpSrcDIB);
LONG lSrcHeight = DIBHeight(lpSrcDIB);
WORD bitSrcCnt = DIBBitCount(lpSrcDIB);
LONG lSrcBytePerLine = MYWIDTHBYTES(lSrcWidth * bitSrcCnt);
if( bitCnt != bitSrcCnt || bitCnt < 8 )
goto CleanUp;
LPBYTE lpSrcDIBBits = FindDIBBits(lpSrcDIB);
LONG lDstWidth, lDstHeight, lDstBytesPerLine, i, j, k;
HDIB hDIB = NULL;
LPBYTE lpDstDIB, lpDstDIBBits;
lpDstDIB = lpDstDIBBits = NULL;
switch (nMethod)
{
case 0:
case 1:
lDstHeight = lSrcHeight + lHeight;
lDstWidth = max(lWidth, lSrcWidth);
break;
case 2:
case 3:
default:
lDstHeight = max(lSrcHeight, lHeight);
lDstWidth = lWidth + lSrcWidth;
}
lDstBytesPerLine = MYWIDTHBYTES(lDstWidth*bitCnt);
// 分配内存,以保存新DIB
hDIB = (HDIB) ::GlobalAlloc(GHND, lDstBytesPerLine * lDstHeight + *(LPDWORD)lpDIB + ::PaletteSize(lpDIB));
if( hDIB == NULL )
goto CleanUp;
lpDstDIB = (LPBYTE)GlobalLock(hDIB);
// 获取指针
LPBITMAPINFOHEADER lpbmi = (LPBITMAPINFOHEADER)lpDstDIB;
LPBITMAPCOREHEADER lpbmc = (LPBITMAPCOREHEADER)lpDstDIB;
// 复制DIB信息头和调色板
memcpy(lpDstDIB, lpDIB, *(LPDWORD)lpDIB + PaletteSize(lpDIB));
lpDstDIBBits = lpDstDIB + *(LPDWORD)lpDIB + ::PaletteSize(lpDIB);
memset(lpDstDIBBits, 255, lDstBytesPerLine * lDstHeight * sizeof(BYTE));
switch (nMethod)
{
case 0: //上下结构,Src位于图像的下半部分
for( i = 0, j = 0, k = 0; i < lSrcHeight; i++, j += lDstBytesPerLine, k += lSrcBytePerLine )
{
memcpy(lpDstDIBBits + j, lpSrcDIBBits + k, lSrcBytePerLine);
}
for( i = lSrcHeight, j = i * lDstBytesPerLine, k = 0; i < lDstHeight; i++, j += lDstBytesPerLine, k += lBytePerLine )
{
memcpy(lpDstDIBBits + j, lpDIBBits + k, lBytePerLine );
}
break;
case 1: //上下结构,当前图像位于合并后图像的下半部分
for( i = 0, j = 0, k = 0; i < lHeight; i++, j += lDstBytesPerLine, k += lBytePerLine )
{
memcpy(lpDstDIBBits + j, lpDIBBits + k, lBytePerLine);
}
for( i = lHeight, j = i * lDstBytesPerLine, k = 0; i < lDstHeight; i++, j += lDstBytesPerLine, k += lSrcBytePerLine )
{
memcpy(lpDstDIBBits + j, lpSrcDIBBits + k, lSrcBytePerLine );
}
break;
case 2: //左右结构,Src图像位于合并后图像的右半部分
for( i = 0, j = 0, k = 0; i < lHeight; i++, j += lDstBytesPerLine, k += lBytePerLine)
{
memcpy(lpDstDIBBits + j, lpDIBBits + k, lBytePerLine);
}
for( i = 0, j = lBytePerLine, k = 0; i < lSrcHeight; i++, j += lDstBytesPerLine, k += lSrcBytePerLine )
{
memcpy(lpDstDIBBits + j, lpSrcDIBBits + k, lSrcBytePerLine);
}
break;
case 3: //左右结构,当前图像位于合并后图像的右半部分
default:
for( i = lSrcHeight - 1, j = i * lDstBytesPerLine, k = i * lSrcBytePerLine; i >= 0; i--, j -= lDstBytesPerLine, k -= lSrcBytePerLine)
{
memcpy(lpDstDIBBits + j, lpSrcDIBBits + k, lSrcBytePerLine);
}
for( i = lHeight - 1, j = i * lDstBytesPerLine + lSrcBytePerLine, k = i * lBytePerLine; i >= 0; i--, j -= lDstBytesPerLine, k -= lBytePerLine )
{
memcpy(lpDstDIBBits + j, lpDIBBits + k, lBytePerLine);
}
break;
}
// 更新DIB中图像的高度和宽度
if (IS_WIN30_DIB(lpDIB))
{
// 对于Windows 3.0 DIB
lpbmi->biWidth = lDstWidth;
lpbmi->biHeight = lDstHeight;
}
else
{
// 对于其它格式的DIB
lpbmc->bcWidth = (unsigned short) lDstWidth;
lpbmc->bcHeight = (unsigned short) lDstHeight;
}
bSuccess = true;
CleanUp:
GlobalUnlock(m_hDib);
GlobalFree(m_hDib);
GlobalUnlock(pSrcArd->m_hDib);
if( bSuccess && hDIB != NULL )
m_hDib = hDIB;
if( bSuccess )
return UpdateInternal();
else
return bSuccess;
}
/******************************************************************
功能:将两幅图像合并为一幅图像
输入:
pSrcArd:输入的CArdpsImg对象,图像的句柄存于该对象中
nPos1: 当前图像的合并坐标;
nPos2 输入的CArdpsImg对象,合并图像的坐标
nMethod:0:上下合并,取当前图像的下部,pSrcArd图像的上部
1:左右合并,取当前图像的右部,pSrcArd图像的下部
输出:
当前图像为合并后的图像,合并成功返回true
******************************************************************/
bool CArdpsImg::MergeImage(CArdpsImg *pSrcArd, int nPos1, int nPos2, int nMethod /* = 0 */)
{
bool bSuccess = false;
if( pSrcArd == NULL )
return bSuccess;
//当前图像
LPBYTE lpDIB = (LPBYTE)GlobalLock(m_hDib);
LONG lWidth = DIBWidth(lpDIB);
LONG lHeight = DIBHeight(lpDIB);
WORD bitCnt = DIBBitCount(lpDIB);
LONG lBytePerLine = MYWIDTHBYTES(lWidth * bitCnt);
LPBYTE lpDIBBits = FindDIBBits(lpDIB);
//欲合并的图像
LPBYTE lpSrcDIB = (LPBYTE)GlobalLock(pSrcArd->m_hDib);
LONG lSrcWidth = DIBWidth(lpSrcDIB);
LONG lSrcHeight = DIBHeight(lpSrcDIB);
WORD bitSrcCnt = DIBBitCount(lpSrcDIB);
LONG lSrcBytePerLine = MYWIDTHBYTES(lSrcWidth * bitSrcCnt);
if( bitCnt != bitSrcCnt || bitCnt < 8 )
goto CleanUp;
LPBYTE lpSrcDIBBits = FindDIBBits(lpSrcDIB);
LONG lDstWidth, lDstHeight, lDstBytesPerLine, i, j, k;
HDIB hDIB = NULL;
LPBYTE lpDstDIB, lpDstDIBBits;
lpDstDIB = lpDstDIBBits = NULL;
nPos1 -= 1;
nPos2 -= 1;
switch (nMethod)
{
case 0:
if( nPos1 >= lHeight )
nPos1 = lHeight - 1;
if( nPos1 < 0 )
nPos1 = 0;
if( nPos2 >= lSrcHeight )
nPos2 = lSrcHeight - 1;
if( nPos2 < 0 )
nPos2 = 0;
lDstHeight = nPos2 + lHeight - nPos1;
lDstWidth = max(lWidth, lSrcWidth);
break;
case 1:
if (nPos1 >= lWidth )
nPos1 = lWidth - 1;
if( nPos1 < 0 )
nPos1 = 0;
if( nPos2 >= lSrcWidth )
nPos2 = lSrcWidth - 1;
if( nPos2 < 0 )
nPos2 = 0;
lDstHeight = max(lSrcHeight, lHeight);
lDstWidth = lWidth - nPos1 + nPos2;
}
lDstBytesPerLine = MYWIDTHBYTES(lDstWidth*bitCnt);
// 分配内存,以保存新DIB
hDIB = (HDIB) ::GlobalAlloc(GHND, lDstBytesPerLine * lDstHeight + *(LPDWORD)lpDIB + ::PaletteSize(lpDIB));
if( hDIB == NULL )
goto CleanUp;
lpDstDIB = (LPBYTE)GlobalLock(hDIB);
// 获取指针
LPBITMAPINFOHEADER lpbmi = (LPBITMAPINFOHEADER)lpDstDIB;
LPBITMAPCOREHEADER lpbmc = (LPBITMAPCOREHEADER)lpDstDIB;
// 复制DIB信息头和调色板
memcpy(lpDstDIB, lpDIB, *(LPDWORD)lpDIB + PaletteSize(lpDIB));
lpDstDIBBits = lpDstDIB + *(LPDWORD)lpDIB + ::PaletteSize(lpDIB);
memset(lpDstDIBBits, 255, lDstBytesPerLine * lDstHeight * sizeof(BYTE));
int nLength = 0;
switch (nMethod)
{
case 0: //上下结构,当前图像位于合并图像的下半部分
for( i = 0, j = 0, k = 0; i < lHeight - nPos1; i++, j += lDstBytesPerLine, k += lBytePerLine )
{
memcpy(lpDstDIBBits + j, lpDIBBits + k, lBytePerLine);
}
for( i = lSrcHeight - nPos2 , k = i * lSrcBytePerLine; i < lSrcHeight; i++, j += lDstBytesPerLine, k += lSrcBytePerLine )
{
memcpy(lpDstDIBBits + j, lpSrcDIBBits + k, lSrcBytePerLine );
}
break;
case 1: //左右结构,当前图像位于合并后图像的右半部分
nLength = nPos2 * bitCnt / 8;
for( i = 0, k = 0, j = 0; i < lSrcHeight; i++, k += lSrcBytePerLine, j += lDstBytesPerLine )
{
memcpy(lpDstDIBBits + j, lpSrcDIBBits + k, nLength);
}
nLength = (lWidth - nPos1) * bitCnt / 8;
for( i = 0, k = nPos1 * bitCnt / 8, j = nPos2 * bitCnt / 8; i < lHeight; i++, k+= lBytePerLine, j += lDstBytesPerLine )
{
memcpy(lpDstDIBBits + j, lpDIBBits + k, nLength);
}
break;
}
// 更新DIB中图像的高度和宽度
if (IS_WIN30_DIB(lpDIB))
{
// 对于Windows 3.0 DIB
lpbmi->biWidth = lDstWidth;
lpbmi->biHeight = lDstHeight;
}
else
{
// 对于其它格式的DIB
lpbmc->bcWidth = (unsigned short) lDstWidth;
lpbmc->bcHeight = (unsigned short) lDstHeight;
}
bSuccess = true;
CleanUp:
GlobalUnlock(m_hDib);
GlobalFree(m_hDib);
GlobalUnlock(pSrcArd->m_hDib);
if( bSuccess && hDIB != NULL )
m_hDib = hDIB;
if( bSuccess )
return UpdateInternal();
else
return bSuccess;
}
////////////////////////////////////////////////////////////////////////////////
/**
* Changes the brightness and the contrast of the image. Apply a look up table to the image.
* \ * \param brightness: can be from -255 to 255, if brightness is negative, the image becomes dark.
* \param contrast: can be from -100 to 100, the neutral value is 0.
* \return true if everything is ok
*/
bool CArdpsImg::AjustLightAndContrast(int brightness, int contrast)
{
if (!m_hDib) return false;
float c=(100 + contrast)/100.0f;
brightness+=128;
long i;
BYTE cTable[256]; //<nipper>
for ( i=0;i<256;i++) {
cTable[i] = (BYTE)max(0,min(255,(int)((i-128)*c + brightness + 0.5f)));
}
LPBYTE lpDIB = (LPBYTE)GlobalLock(m_hDib);
if( lpDIB == NULL )
return false;
LONG lWidth = DIBWidth(lpDIB);
LONG lHeight = DIBHeight(lpDIB);
WORD bitCnt = DIBBitCount(lpDIB);
LONG lBytePerLine = MYWIDTHBYTES(lWidth * bitCnt);
LPBYTE lpDIBBits = FindDIBBits(lpDIB);
RGBQUAD *pRgb =(RGBQUAD *)( lpDIB + 40);
if (bitCnt == 8)
{
for( i = 0; i < 256; i++)
{
pRgb[i].rgbBlue = pRgb[i].rgbRed = pRgb[i].rgbGreen = cTable[i];
}
}
else if( bitCnt == 24)
{
for( i = 0; i < lBytePerLine * lHeight; i++)
{
*lpDIBBits++ = cTable[*lpDIBBits];
}
}
else
{
GlobalUnlock(m_hDib);
return false;
}
GlobalUnlock(m_hDib);
return UpdateInternal();
}
/******************************************************************
功能:自动分析边框,并进行调整,不改变图像的大小
输入:
nMethod:0:从水平,垂直两个方向上进行调整。
1:水平调整
2:垂直调整
输出:
调整后的图像,成功返回true
******************************************************************/
bool CArdpsImg::AdjustBinPos(int nMethod /* = 0 */)
{
LPBYTE lpDIB = (LPBYTE)GlobalLock(m_hDib);
if( lpDIB == NULL )
return false;
LONG lWidth = DIBWidth(lpDIB);
LONG lHeight = DIBHeight(lpDIB);
WORD bitCnt = DIBBitCount(lpDIB);
LONG lBytePerLine = MYWIDTHBYTES(lWidth * bitCnt);
LPBYTE lpDIBBits = FindDIBBits(lpDIB);
if( bitCnt != 1 )
{
GlobalUnlock(m_hDib);
return false;
}
//for gray image
LONG nGrayBytesPerLine = MYWIDTHBYTES( lWidth << 3 );
LONG nGrayImgSize = nGrayBytesPerLine * lHeight;
BYTE *pbGrayImg = new BYTE[nGrayImgSize];
if( !pbGrayImg )
{
GlobalUnlock(m_hDib);
return false;
}
bool bSuccess = ConvertBinary2Gray(lpDIBBits, lWidth, lHeight, pbGrayImg );
if( !bSuccess )
{
GlobalUnlock(m_hDib);
delete []pbGrayImg;
pbGrayImg = NULL;
return false;
}
RECT rtImg = GetBinImageBoundary(pbGrayImg, lWidth, lHeight);
RECT rtNew;
rtNew.left = (rtImg.left + lWidth - rtImg.right )/2;
rtNew.right = lWidth - rtNew.left -1;
rtNew.top = (rtImg.top + lHeight - rtImg.bottom)/2;
rtNew.bottom = lHeight - rtNew.top - 1;
MoveBin(pbGrayImg, lWidth, lHeight, rtImg, rtNew, nMethod );
bSuccess = ThreshImage(pbGrayImg, lpDIBBits, lWidth, lHeight, 10);
if( pbGrayImg )
delete []pbGrayImg;
pbGrayImg = NULL;
GlobalUnlock(m_hDib);
return UpdateInternal();
}
/******************************************************************
功能:彩色图像色阶调整
输入:
输出:
调整后的图像,成功返回true
******************************************************************/
bool CArdpsImg::ColorEqual()
{
LPBYTE lpDIB = (LPBYTE)GlobalLock(m_hDib);
if( lpDIB == NULL )
return false;
LONG lWidth = DIBWidth(lpDIB);
LONG lHeight = DIBHeight(lpDIB);
WORD bitCnt = DIBBitCount(lpDIB);
LONG lBytePerLine = MYWIDTHBYTES(lWidth * bitCnt);
LPBYTE lpDIBBits = FindDIBBits(lpDIB);
if( bitCnt != 24 )
{
GlobalUnlock(m_hDib);
return false;
}
int nHist[256];
long long nCulHist[256];
long long nConver[256];
memset(nHist, 0, 256 * sizeof(int));
memset(nCulHist, 0, 256 * sizeof( long long ));
memset(nConver, 0, 256 * sizeof(long long ));
long i, j, m, newValue;
LPBYTE pSrc = NULL;
for( i = 0, m = 0; i < lHeight; i++, m += lBytePerLine )
{
pSrc = lpDIBBits + m;
for( j = 0; j < lWidth; j++)
{
newValue = (*pSrc) * uiBWeight + uiGWeight * (*(pSrc + 1)) + uiRWeight * (*(pSrc + 2));
newValue /= 1000;
nHist[newValue]++;
pSrc += 3;
}
}
long long nTotal = lHeight * lWidth;
nCulHist[0] = nHist[0];
nConver[0] = nHist[0] * 255 / nTotal;
for( i = 1; i < 256; i++ )
{
nCulHist[i] = nCulHist[i - 1] + nHist[i];
nConver[i] = nCulHist[i] * 255 / nTotal;
}
for( i = 0, m = 0; i < lHeight; i++, m += lBytePerLine )
{
pSrc = lpDIBBits + m;
for( j = 0; j < lWidth; j++)
{
*pSrc = nConver[*pSrc];
pSrc++;
*pSrc = nConver[*pSrc];
pSrc++;
*pSrc = nConver[*pSrc];
pSrc++;
}
}
GlobalUnlock(m_hDib);
return UpdateInternal();
}
bool CArdpsImg::Zoom(double fRatioX, double fRatioY)
{
int nWidth = (int)(fRatioX * (double)GetWidth());
int nHeight = (int)(fRatioY * (double)GetHeight());
HDIB hNewDib = ChangeDIBSize(m_hDib, nWidth, nHeight);
if (! hNewDib)
return false;
// set to m_hDib
Destroy();
m_hDib = hNewDib;
// return
return UpdateInternal();
}
//连通域提取
void CArdpsImg::ExtractComponent(Line * Li, BYTE *pbBinary, UINT grayBytesPerLine, BYTE bCur ) //连通域提取
{
if( Li == NULL || pbBinary == NULL )
return;
int * stack = NULL;
int * InStack[10];
int top, topin;
top = topin = 0;
CPoint temp;
component *ctail =NULL;
component *chead =new component;
InStack[topin] = new int[COMP_NUM];
if( InStack[topin] == NULL )
return;
stack = InStack[topin];
char **flag=new char*[Li->EndY-Li->StartY+1];
if( *flag == NULL )
{
delete []InStack[topin];
InStack[topin] = NULL;
return;
}
int i, j, k;
for(i = 0; i <= Li->EndY - Li->StartY; i++) //寻找连通体
{
flag[i]=new char[Li->EndX - Li->StartX + 1];
for(j = 0; j <= Li->EndX - Li->StartX; j++)
{
flag[i][j]=0;
}
}
for(j = Li->StartX; j <= Li->EndX; j++) //寻找连通体
{
for( i = Li->StartY, k = Li->StartY * grayBytesPerLine; i <= Li->EndY; i++, k += grayBytesPerLine)
{
if(flag[i-Li->StartY][j-Li->StartX] == 0 && pbBinary[k + j] == bCur )
{
stack[top++]=i;
stack[top++]=j;
flag[i - Li->StartY][j - Li->StartX] = 1;
if(ctail!=NULL)
{
component *cp = new component;
ctail->cnext = cp;
ctail = cp;
}
else
{
ctail = chead;
}
ctail->bound =CRect(j,i,j,i);
ctail->count =1;
while(top != 0)
{
temp.x = stack[--top];
temp.y = stack[--top];
if(top == 0 && topin != 0)
{
stack = InStack[topin-1];
delete []InStack[topin--];
top = COMP_NUM;
}
if(temp.x - 1 >= Li->StartX)
add(temp.x-1, temp.y, flag, stack, InStack, top, topin,
Li->StartX, Li->StartY, ctail, pbBinary, grayBytesPerLine, bCur );
if(temp.x+1 <= Li->EndX)
add(temp.x+1, temp.y, flag, stack, InStack, top, topin,
Li->StartX, Li->StartY, ctail, pbBinary, grayBytesPerLine, bCur);
if(temp.y-1 >= Li->StartY)
add(temp.x, temp.y-1, flag, stack, InStack, top, topin,
Li->StartX, Li->StartY, ctail, pbBinary, grayBytesPerLine, bCur);
if(temp.y+1 <= Li->EndY)
add(temp.x, temp.y+1, flag, stack, InStack, top, topin,
Li->StartX, Li->StartY, ctail, pbBinary, grayBytesPerLine, bCur);
if((temp.x-1 >= Li->StartX) && (temp.y - 1 >= Li->StartY))
add(temp.x-1, temp.y-1, flag, stack, InStack, top, topin,
Li->StartX, Li->StartY, ctail, pbBinary, grayBytesPerLine, bCur);
if((temp.x+1 <= Li->EndX) && (temp.y-1 >= Li->StartY))
add(temp.x+1, temp.y-1, flag, stack, InStack, top, topin,
Li->StartX, Li->StartY, ctail, pbBinary, grayBytesPerLine, bCur);
if((temp.x-1 >= Li->StartX) && (temp.y+1 <= Li->EndY))
add(temp.x-1, temp.y+1, flag, stack, InStack, top, topin,
Li->StartX, Li->StartY, ctail, pbBinary, grayBytesPerLine, bCur);
if((temp.x+1 <= Li->EndX) && (temp.y+1 <= Li->EndY))
add(temp.x+1, temp.y+1, flag, stack, InStack, top, topin,
Li->StartX, Li->StartY, ctail, pbBinary, grayBytesPerLine, bCur);
}
}
}
} //end for
Li->cp = chead;
delete []stack;
for(i = 0; i <= Li->EndY-Li->StartY; i++)
delete []flag[i];
delete []flag;
}
void CArdpsImg::add(int a,int b,char **flag,int *&stack,int **InStack,
int &top,int &topin,int c,int d,component *ctail, BYTE *pMotion, UINT grayBytesPerLine, BYTE bCur )
{
if((flag[b-d][a-c] == 0 ) && pMotion[b * grayBytesPerLine + a] == bCur )
{
flag[b-d][a-c] = 1;
if(top == COMP_NUM)
{
if(topin == 9)
{
return;
}
InStack[++topin]=new int[COMP_NUM];
stack=InStack[topin];
top=0;
}
stack[top++]=b;
stack[top++]=a;
ctail->count++;
if(ctail->bound.bottom < b) //连通体边界
ctail->bound.bottom = b;
if(ctail->bound.top > b)
ctail->bound.top = b;
if(ctail->bound.left > a)
ctail->bound.left = a;
if(ctail->bound.right < a)
ctail->bound.right = a;
}
}
void CArdpsImg::AnalysisComponent( Line * Li, BYTE *pbBinary, UINT unBinaryBytesPerLine, UINT minArea, const BYTE bValue)
{
if( Li == NULL || pbBinary == NULL )
return;
component *cp1= Li->cp;
component *cp2;
int area;//, nCnt = 0;
while( cp1 != NULL )
{
area = cp1->bound.Height() * cp1->bound.Width();
if( area < minArea && area > 0 )
{
SetBinary(cp1->bound, pbBinary, unBinaryBytesPerLine, bValue);
}
cp2 = cp1;
cp1 = cp1->cnext;
delete cp2;
}
Li->cp = NULL;
}
CRect* CArdpsImg::GetDirtPos(int nMethod, int *nCnt)
{
*nCnt = 0;
LPBYTE lpDIB = (LPBYTE)GlobalLock(m_hDib);
if( !lpDIB)
return m_dirRect;
LPBYTE lpBinImg = FindDIBBits(lpDIB);
if( !lpBinImg )
{
GlobalUnlock(m_hDib);
return m_dirRect;
}
bool bSuccess = true;
LONG nImgHei = GetHeight();
LONG nImgWid = GetWidth();
int nBitCnt = DIBBitCount(lpDIB);
if( nBitCnt != 1 )
{
GlobalUnlock(m_hDib);
return m_dirRect;
}
LONG nBinBytesPerLine = MYWIDTHBYTES(nImgWid * nBitCnt);
//for gray image
LONG nGrayBytesPerLine = MYWIDTHBYTES( nImgWid << 3 );
LONG nGrayImgSize = nGrayBytesPerLine * nImgHei;
BYTE *pbGrayImg = new BYTE[nGrayImgSize];
if( !pbGrayImg )
{
GlobalUnlock(m_hDib);
return m_dirRect;
}
bSuccess = ConvertBinary2Gray(lpBinImg, nImgWid, nImgHei, pbGrayImg );
//SaveTo8bit_BMP(pbGrayImg, nImgWid, nImgHei, "d:\\testgray.bmp", 8);
if( !bSuccess )
{
delete []pbGrayImg;
pbGrayImg = NULL;
GlobalUnlock(m_hDib);
return m_dirRect;
}
Line *Li = new Line;
if( !Li )
{
delete []pbGrayImg;
pbGrayImg = NULL;
GlobalUnlock(m_hDib);
return m_dirRect;
}
Li->StartY = 3;
Li->StartX = 3;
Li->EndX = nImgWid - 3;
Li->EndY = nImgHei - 3;
Li->cp = NULL;
BYTE bCur;
if( nMethod == 0 ) //黑色为背景
{
bCur = 0;
}
else
{
bCur = 255;
}
ExtractComponent(Li, pbGrayImg, nGrayBytesPerLine, bCur );
AnalysisDirtPos(Li, m_DirtSize, m_minDirtSize, nImgHei, nCnt);
if( pbGrayImg )
{
delete []pbGrayImg;
pbGrayImg = NULL;
}
if( Li )
{
delete Li;
Li = NULL;
}
GlobalUnlock(m_hDib);
return m_dirRect;
}
bool CArdpsImg::AnalysisDirtPos(Line *Li, CSize maxSize, CSize minSize, int nHeight, int *nCnt)
{
if( Li == NULL || nCnt == NULL )
return false;
component *cp1= Li->cp;
component *cp2;
int area;//, nCnt = 0;
int minArea = minSize.cx * minSize.cy;
int maxArea = maxSize.cx * maxSize.cy;
*nCnt = 0;
while(cp1 != NULL )
{
cp1 = cp1->cnext;
(*nCnt)++;
}
if( m_dirRect )
{
delete []m_dirRect;
m_dirRect = NULL;
}
m_dirRect = new CRect[(*nCnt)];
if( m_dirRect == NULL )
return false;
cp1= Li->cp;
*nCnt = 0;
while( cp1 != NULL )
{
area = cp1->bound.Height() * cp1->bound.Width();
if( area <= maxArea && area >= minArea )
{
m_dirRect[*nCnt].top = nHeight - 1 - cp1->bound.bottom;
m_dirRect[*nCnt].bottom = nHeight - 1 - cp1->bound.top;
m_dirRect[*nCnt].left = cp1->bound.left;
m_dirRect[*nCnt].right = cp1->bound.right;
(*nCnt)++;
}
cp2 = cp1;
cp1 = cp1->cnext;
delete cp2;
}
Li->cp = NULL;
return true;
}
void CArdpsImg::SetBinary(CRect rect, BYTE *pbImg, UINT unBinaryBytesPerLine, const BYTE bValue)
{
if( pbImg == NULL )
return;
LONG i, j, m;
for( i = rect.top, m = rect.top * unBinaryBytesPerLine; i <= rect.bottom; i++, m += unBinaryBytesPerLine )
{
for( j = rect.left; j <= rect.right; j++ )
{
*(pbImg + m + j) = bValue;
}
}
}
bool CArdpsImg::ConvertBinary2Gray(const unsigned char * pbBinary, const int nWidth, const int nHeight, unsigned char *pbGray)
{
if( pbBinary == NULL || pbGray == NULL || nWidth < 1 || nHeight < 1)
return false;
LONG nBinaryBytesPerLine = MYWIDTHBYTES(nWidth);
LONG nGrayBytesPerLine = MYWIDTHBYTES(nWidth << 3);
LONG i, j, k, m;
const unsigned char * pbIn = pbBinary;
unsigned char * pbOut = pbGray;
memset( pbGray, 0, nHeight * nGrayBytesPerLine * sizeof( unsigned char));
BYTE btmp = 0;
for( i = 0, k = 0, m = 0; i < nHeight; i++, k += nGrayBytesPerLine, m += nBinaryBytesPerLine )
{
pbIn = pbBinary + m;
pbOut = pbGray + k;
for( j = 0; j < (nWidth + 7)/8; j++, pbIn++)
{
btmp = *pbIn;
btmp = btmp & 128 ;
if( btmp == 128)
*pbOut = 255;
pbOut ++;
btmp = *pbIn;
btmp = btmp & 64 ;
if( btmp == 64)
*pbOut = 255;
pbOut ++;
btmp = *pbIn;
btmp = btmp & 32 ;
if( btmp == 32)
*pbOut = 255;
pbOut ++;
btmp = *pbIn;
btmp = btmp & 16 ;
if( btmp == 16)
*pbOut = 255;
pbOut ++;
btmp = *pbIn;
btmp = btmp & 8 ;
if( btmp == 8)
*pbOut = 255;
pbOut ++;
btmp = *pbIn;
btmp = btmp & 4 ;
if( btmp == 4)
*pbOut = 255;
pbOut ++;
btmp = *pbIn;
btmp = btmp & 2 ;
if( btmp == 2)
*pbOut = 255;
pbOut ++;
btmp = *pbIn;
btmp = btmp & 1;
if( btmp == 1)
*pbOut = 255;
pbOut ++;
}
}
return true;
}
bool CArdpsImg::FindTopEdge(BYTE *pbOutImage, BYTE *image, RECT rtROI, int nWidth)
{
if( pbOutImage == NULL || image == NULL )
return false;
BYTE *pbIn1, *pbIn2;
pbIn2 = pbIn1 = NULL;
int i, j;
int gd, n = 0, k = 0;
int d;
gd = n = 0;
pbIn1 = image + (rtROI.top + EDGE_STEP) * nWidth + rtROI.left;
for (i = rtROI.top + EDGE_STEP; i < rtROI.bottom; i++, pbIn1 += nWidth)
{
pbIn2 = pbIn1;
for (j = rtROI.left; j < rtROI.right; j++, pbIn2++)
{
d = pbIn2[-EDGE_STEP * nWidth] - pbIn2[0];
if (d > 20)
{
gd += d;
n++;
}
}
}
if (n > 0)
{
gd = gd / n;
}
pbIn1 = image + rtROI.top * nWidth + rtROI.left;
for (i = rtROI.top; i < rtROI.bottom; i++, pbIn1 += nWidth)
{
pbIn2 = pbIn1;
for (j = rtROI.left; j < rtROI.right; j++, pbIn2++)
{
n = (int)(pbIn2 - image);
pbOutImage[n] = 0;
if (j > EDGE_STEP)
{
d = pbIn2[nWidth - EDGE_STEP] - pbIn2[0];
if (d > gd)
{
pbOutImage[n] = 255;
}
}
}
}
for (i = rtROI.top; i < rtROI.bottom; i++)
{
for (j = rtROI.right; j > rtROI.left; j--)
{
if (pbOutImage[i * nWidth + j] <= pbOutImage[i * nWidth + j - 1])
{
pbOutImage[i * nWidth + j] = 0;
}
}
}
return true;
}
double CArdpsImg::DetectSkewAngle(BYTE *pbImage, RECT rtROI, int nWidth)
{
double dK = 0.0;
int i;
int nValeSum, nValeMax, angle;
int *pnRamBuff = NULL;
pnRamBuff = new int[nWidth * 2];
if (pnRamBuff == NULL)
{
return 0.0;
}
angle = nValeMax = 0;
for (i = -10; i <= 10; i ++)
{
nValeSum = CompVPrjValeSum(pnRamBuff, pbImage, nWidth, rtROI.bottom, i);
if(nValeSum>nValeMax)
{
nValeMax = nValeSum;
angle = i;
}
}
dK = angle;// * 3.14159265 / 180;
if( pnRamBuff)
{
delete []pnRamBuff;
pnRamBuff = NULL;
}
return dK;
}
// compute all vale sum
int CArdpsImg::CompVPrjValeSum(int *pnRamBuff, const BYTE *pInImg, int nImgWidth, int nImgHeight, int nRotAngle)
{
if( pnRamBuff == NULL || pInImg == NULL )
return 0;
int nValeSum = 0;
int i, j;
int *nVprj = pnRamBuff, *nPlot = NULL;
int nPrjLen;
int nPrjOffset;
int nPx;
int nSin, nCos;
const BYTE *pb = NULL;
if((nRotAngle >= 0) && (nRotAngle <= 90))
{
nSin = g_nSin[nRotAngle];
nCos = g_nCos[nRotAngle];
}
else if ((nRotAngle < 0)&&(nRotAngle > -90))
{
nSin = -g_nSin[-nRotAngle];
nCos = g_nCos[-nRotAngle];
}
// compute max project length
i = nSin > 0 ? nSin : -nSin;
nPrjLen = nImgWidth*nCos+nImgHeight*i+32768;
nPrjLen = nPrjLen>>16;
if (nPrjLen>nImgWidth)
{
nPrjLen = nImgWidth;
}
if (nSin<0)
{
nPrjOffset = -nImgHeight*nSin+32768;
nPrjOffset = nPrjOffset>>16;
}
else
{
nPrjOffset = 0;
}
memset(nVprj, 0, nPrjLen * 2 * sizeof(int));
nPlot = nVprj + nPrjLen;
pb = pInImg;
for (i = 0; i < nImgHeight; i++)
{
for (j = 0; j < nImgWidth; j++, pb++)
{
if (*pb < 8)
continue;
nPx = j * nCos + i * nSin + 32768;
nPx = (nPx >> 16) + nPrjOffset;
if((nPx < nPrjLen) && (nPx>=0))
{
nVprj[nPx] += *pb;
}
}
}
SmoothingArray(nPlot, 1, nVprj, 0, nPrjLen);
nValeSum = 0;
for(i = 0; i < nPrjLen; i++)
{
if (nPlot[i]==0)
{
nValeSum++;
}
}
return nValeSum;
}
//--------------------------------------------------------------------
// NAME: SmoothingArray
// PARAMS: int *pIn, input array
// int *pOut, output array
// int nR, smooth radius
// int nStart, int nEnd, the begin and end of smoothing
// RETURN: NULL
// FUNCTION: Smoothing one-dimentional array
//---------------------------------------------------------------------
void CArdpsImg::SmoothingArray(int *pOut, int nR, const int *pIn, int nStart, int nEnd)
{
if( pIn == NULL || pOut == NULL )
return;
int i, nSum, nCount;
int beg, end;
nSum = 0;
// the len is less than nR
if (nEnd - nStart <= nR + 1)
{
nCount = nEnd - nStart;
if (nCount <= 0)
{
pOut[nStart] = pIn[nStart];
return;
}
nSum = 0;
for (i = nStart; i < nEnd; i ++)
{
nSum += pIn[i];
}
nSum = (nSum + (nCount >> 1)) / nCount;
for (i = nStart; i < nEnd; i ++)
{
pOut[i] = nSum;
}
return;
}
// first nR len
beg = nStart;
end = nStart + nR;
if (end > nEnd) end = nEnd;
for (i = beg; i < end; i ++)
{
nSum += pIn[i];
}
nCount = end - beg;
// from start to start + nR, maybe less than start + nR
if (end >= nEnd-nR)
end = nEnd - nR - 1;
for (i = nStart; i <= end; i ++)
{
nSum += pIn[i + nR];
nCount ++;
pOut[i] = (nSum + (nCount >> 1)) / nCount;
}
// from start+nR to end - nR
end = nEnd - nR;
for (; i < end; i ++)
{
nSum += pIn[i + nR] - pIn[i - nR - 1];
pOut[i] = (nSum + nCount / 2) / nCount;
}
// from end-nR to start + nR
end = nStart + nR + 1;
if (end > nEnd) end = nEnd;
for (; i < end; i++)
{
pOut[i] = (nSum + nCount / 2) / nCount;
}
// the last nR
beg = i;
if (beg < nStart + nR + 1) beg = nStart + nR + 1;
for (i = beg; i < nEnd; i ++)
{
nCount --;
nSum -= pIn[i - nR - 1];
pOut[i] = (nSum + nCount / 2) / nCount;
}
return;
}
//-------------------------------------------------------
// delete short vertical stroke
//-------------------------------------------------------
int CArdpsImg::DeleteVtlSmallLine(BYTE* pImg, BYTE* pBuf, int nWidth, int nHeight, int nTh)
{
if( pImg == NULL || pBuf == NULL )
return 0;
int i, j, nTop, nBtm, nLen;
int top, btm;
BYTE *pIn, *pIn1, *pb, *pb1;
pb = pb1 = pIn = pIn1 = NULL;
int hr = 0;
top = 0;
btm = nHeight;
LONG nBytesPerLine = MYWIDTHBYTES(nWidth * 8);
memset(pBuf, 0, nBytesPerLine * nHeight);
pIn = pImg + top * nBytesPerLine;
pb = pBuf + top * nBytesPerLine;
for (i = top; i < btm; i++)
{
for (j = 0; j < nWidth; j++, pIn++, pb++)
{
if (*pIn == 0)
{
continue;
}
nTop = i-1;
pIn1 = pIn - nBytesPerLine;
pb1 = pb - nBytesPerLine;
for (; nTop >= 0 && *pIn1 != 0; nTop--, pIn1 -= nBytesPerLine, pb1 -= nBytesPerLine)
{
*pb1 = *pIn1;
*pIn = 0;
}
nTop++;
nBtm = i+1;
pIn1 = pIn + nBytesPerLine;
pb1 = pb + nBytesPerLine;
for (; nBtm < nHeight && *pIn1 != 0; nBtm++, pIn1 += nBytesPerLine, pb1 += nBytesPerLine)
{
*pb1 = *pIn1;
*pIn1 = 0;
}
nBtm --;
nLen = nBtm - nTop + 1;
if (nLen < nTh)
{
pb1 = pBuf + nTop * nBytesPerLine + j;
for (; nTop <= nBtm; nTop++, pb1 += nBytesPerLine)
{
*pb1 = 0;
}
}
}
}
memcpy(pImg, pBuf, nBytesPerLine*nHeight);
return 0;
}
RECT CArdpsImg::GetEdgeImageBoundary(BYTE *pbImage, int nWidth, int nHeight)
{
RECT rect;
BYTE *pbIn1, *pbIn2;
LONG i, j, m;
LONG n, d;
int *pnProjX = NULL, *pnProjY = NULL;
rect = SetRectValue(0, 0, 0, 0);
if( pbImage == NULL )
return rect;
LONG nBytesPerLine = MYWIDTHBYTES(nWidth<< 3);
pnProjX = new int [nWidth + nHeight];
if (pnProjX == NULL)
{
return rect;
}
pnProjY = pnProjX + nWidth;
memset(pnProjX, 0, (nWidth + nHeight) * sizeof(int));
for (i = 0, m = 0; i < nHeight; i++, m+= nBytesPerLine )
{
pnProjY[i] = 0;
pbIn1 = pbImage + m;
for (j = 0; j < nWidth; j++, pbIn1++)
{
pnProjY[i] += pbIn1[0];
}
}
pbIn1 = pbImage;
for (i = 0; i < nWidth; i++, pbIn1++)
{
pbIn2 = pbIn1;
pnProjX[i] = 0;
for (j = 0; j < nHeight; j++, pbIn2 += nBytesPerLine)
{
pnProjX[i] += pbIn2[0];
}
}
d = n = 0;
for (i = 0; i < nHeight; i++)
{
d += pnProjY[i];
n++;
}
d = d / (4 * n);
rect.top = 0;
for (i = 0; i < nHeight; i++)
{
if (pnProjY[i] > d)
{
rect.top = i;
break;
}
}
rect.top = rect.top > 1 ? (rect.top - 1) : rect.top;
rect.bottom = nHeight - 1;
for (i = nHeight - 1; i >= 0; i--)
{
if (pnProjY[i] > d)
{
rect.bottom = i;
break;
}
}
rect.bottom = rect.bottom < (nHeight - 2) ? (rect.bottom + 1) : rect.bottom;
d = n = 0;
for (i = 0; i < nWidth; i++)
{
d += pnProjX[i];
n++;
}
d = d / (4 * n);
rect.left = 0;
for (i = 0; i < nWidth; i++)
{
if (pnProjX[i] > d)
{
rect.left = i;
break;
}
}
rect.left = rect.left > 0 ? (rect.left - 1) : rect.left;
rect.right = nWidth - 1;
for (i = nWidth - 1; i >= 0; i--)
{
if (pnProjX[i] > d)
{
rect.right = i;
break;
}
}
rect.right = rect.right < (nWidth - 2) ? (rect.right + 1) : rect.right;
if (pnProjX != NULL)
{
delete []pnProjX;
pnProjX = NULL;
}
return rect;
}
void CArdpsImg::MoveBin(BYTE *pbIn, int nWidth, int nHeight, RECT rtOld, RECT rtNew, int nMethod)
{
if( !pbIn )
return;
LONG lBytesPerLine = MYWIDTHBYTES(nWidth << 3);
LONG lImgSize = lBytesPerLine * nHeight;
BYTE *pbOut = new BYTE[lImgSize];
if( pbOut == NULL )
return;
memset(pbOut, 255, lImgSize * sizeof(BYTE));
LONG i, j, m, n;
BYTE *pbTmpIn = NULL;
switch (nMethod)
{
case 1: //水平调整
j = rtOld.right - rtOld.left + 1;
for (i = 0, m = 0; i < nHeight; i++, m += lBytesPerLine )
{
memcpy(pbOut + rtNew.left+ m, pbIn + rtOld.left + m, j * sizeof(BYTE) );
}
break;
case 2: //垂直调整
//i = rtOld.bottom - rtOld.top + 1;
i = rtNew.top * lBytesPerLine;
for( j = rtOld.top, m = j * lBytesPerLine; j <= rtOld.bottom; j++, m += lBytesPerLine)
{
memcpy(pbOut + i, pbIn + m, lBytesPerLine);
i += lBytesPerLine;
}
break;
case 0: //垂直和水平调整
default:
i = rtNew.top * lBytesPerLine + rtNew.left;
m = rtOld.top *lBytesPerLine + rtOld.left;
n = rtOld.right - rtOld.left + 1;
for( j = rtOld.top; j <= rtOld.bottom; j++)
{
memcpy(pbOut + i, pbIn + m, n * sizeof(BYTE));
i += lBytesPerLine;
m += lBytesPerLine;
}
break;
}
memcpy( pbIn, pbOut, lImgSize * sizeof(BYTE));
if( pbOut )
delete[]pbOut;
pbOut = NULL;
}
RECT CArdpsImg::GetBinImageBoundary(BYTE *pbImage, int nWidth, int nHeight)
{
RECT rect;
BYTE *pbIn1, *pbIn2;
LONG i, j, m;
LONG n, d;
int *pnProjX = NULL, *pnProjY = NULL;
rect = SetRectValue(0, 0, 0, 0);
if( pbImage == NULL )
return rect;
LONG nBytesPerLine = MYWIDTHBYTES(nWidth<< 3);
pnProjX = new int [nWidth + nHeight];
if (pnProjX == NULL)
{
return rect;
}
pnProjY = pnProjX + nWidth;
memset(pnProjX, 0, (nWidth + nHeight) * sizeof(int));
for (i = 0, m = 0; i < nHeight; i++, m+= nBytesPerLine )
{
pnProjY[i] = 0;
pbIn1 = pbImage + m;
for (j = 0; j < nWidth; j++, pbIn1++)
{
pnProjY[i] += 255- pbIn1[0];
}
pnProjY[i] /= 255;
}
pbIn1 = pbImage;
for (i = 0; i < nWidth; i++, pbIn1++)
{
pbIn2 = pbIn1;
pnProjX[i] = 0;
for (j = 0; j < nHeight; j++, pbIn2 += nBytesPerLine)
{
pnProjX[i] += 255- pbIn2[0];
}
pnProjX[i] /= 255;
}
d = n = 0;
for (i = 0; i < nHeight; i++)
{
d += pnProjY[i];
n++;
}
d = d / (4 * n);
rect.top = 0;
for (i = 0; i < nHeight; i++)
{
if (pnProjY[i] > d)
{
rect.top = i;
break;
}
}
rect.top = rect.top > 1 ? (rect.top - 1) : rect.top;
rect.bottom = nHeight - 1;
for (i = nHeight - 1; i >= 0; i--)
{
if (pnProjY[i] > d)
{
rect.bottom = i;
break;
}
}
rect.bottom = rect.bottom < (nHeight - 2) ? (rect.bottom + 1) : rect.bottom;
d = n = 0;
for (i = 0; i < nWidth; i++)
{
d += pnProjX[i];
n++;
}
d = d / (4 * n);
rect.left = 0;
for (i = 0; i < nWidth; i++)
{
if (pnProjX[i] > d)
{
rect.left = i;
break;
}
}
rect.left = rect.left > 0 ? (rect.left - 1) : rect.left;
rect.right = nWidth - 1;
for (i = nWidth - 1; i >= 0; i--)
{
if (pnProjX[i] > d)
{
rect.right = i;
break;
}
}
rect.right = rect.right < (nWidth - 2) ? (rect.right + 1) : rect.right;
if (pnProjX != NULL)
{
delete []pnProjX;
pnProjX = NULL;
}
return rect;
}
RECT CArdpsImg::SetRectValue(int left, int right, int top, int bottom)
{
RECT rect;
rect.left = left;
rect.right = right;
rect.top = top;
rect.bottom = bottom;
return rect;
}
int CArdpsImg::FindEdgeImage(BYTE *pbOutImage, BYTE *image, RECT rtROI, int nWidth)
{
if( pbOutImage == NULL || image == NULL )
return -1;
BYTE *pbIn1, *pbIn2;
int i, j, d;
int gd, n = 0, k = 0;
pbIn2 = pbIn1 = NULL;
int nBytesPerLine = MYWIDTHBYTES(nWidth << 3);
gd = n = 0;
pbIn1 = image + rtROI.top * nBytesPerLine + rtROI.left;
for (i = rtROI.top; i < rtROI.bottom; i++, pbIn1 += nBytesPerLine)
{
pbIn2 = pbIn1 + EDGE_STEP;
for (j = rtROI.left + EDGE_STEP; j < rtROI.right; j++, pbIn2++)
{
d = pbIn2[-EDGE_STEP] - pbIn2[0];
if (d < 10)
{
continue;
}
gd += d;
n++;
}
}
if (n < 100)
{
return -1;
}
gd = gd / n;
pbIn1 = image + rtROI.top * nBytesPerLine + rtROI.left;
for (i = rtROI.top; i < rtROI.bottom; i++, pbIn1 += nBytesPerLine)
{
pbIn2 = pbIn1;
for (j = rtROI.left; j < rtROI.right; j++, pbIn2++)
{
n = (int)(pbIn2 - image);
pbOutImage[n] = 0;
if (j > EDGE_STEP)
{
d = pbIn2[-EDGE_STEP] - pbIn2[0];
if (d > gd)
{
pbOutImage[n] = d;
}
}
if (j < nWidth - EDGE_STEP - 1)
{
d = pbIn2[EDGE_STEP] - pbIn2[0];
if (d > gd && d > pbOutImage[i * nBytesPerLine + j])
{
pbOutImage[n] = d;
}
}
}
}
return 0;
}
HDIB CArdpsImg::ReadBinTiff(char* szImgFileName)
{
TIFF *image = NULL;
uint32 height, buffsize, bytesPerLine, nImgWidth, nPalleteSize, nFileSize;
uint32 row, k, i;
HDIB hDIB = NULL;
// Open the TIFF image
image = TIFFOpen(szImgFileName, "r");
if( image == NULL )
return hDIB;
TIFFGetField(image, TIFFTAG_IMAGELENGTH, &height);
TIFFGetField(image, TIFFTAG_IMAGEWIDTH, &nImgWidth);
uint16 bitspersample=1;
uint16 samplesperpixel=1;
TIFFGetField(image, TIFFTAG_SAMPLESPERPIXEL, &samplesperpixel);
TIFFGetField(image, TIFFTAG_BITSPERSAMPLE, &bitspersample);
//for debug
uint16 compression = 0;
TIFFGetField(image, TIFFTAG_COMPRESSION, &compression);
uint16 photmeric = 0;
TIFFGetField(image, TIFFTAG_PHOTOMETRIC, &photmeric);
uint16 bitsperpixel = bitspersample * samplesperpixel;
if( bitsperpixel == 1)
nPalleteSize = 2;
else if( bitsperpixel == 8 )
nPalleteSize = 256;
else if( bitsperpixel == 16)
return hDIB;
else
nPalleteSize = 0;
buffsize = TIFFScanlineSize(image);
uint32 buffTotalSize = buffsize * height;
BYTE * pbOriImg = new BYTE[buffTotalSize];
if( pbOriImg == NULL )
{
TIFFClose(image);
return hDIB;
}
for (row = 0 , k = (height - 1) * buffsize; row < height; row++ , k -= buffsize )
TIFFReadScanline(image, (void*)(pbOriImg + k), row);
TIFFClose(image);
/*TIFF *newImg = TIFFOpen("d:\\testread.tif", "w");
TIFFSetField(newImg, TIFFTAG_IMAGELENGTH, height);
TIFFSetField(newImg, TIFFTAG_IMAGEWIDTH, nImgWidth);
TIFFSetField(newImg, TIFFTAG_SAMPLESPERPIXEL,samplesperpixel);
TIFFSetField(newImg, TIFFTAG_BITSPERSAMPLE, bitspersample);
TIFFSetField(newImg, TIFFTAG_COMPRESSION, compression);
TIFFSetField(newImg, TIFFTAG_PHOTOMETRIC, photmeric);
for (row = 0 , k = (height - 1) * buffsize; row < height; row++ , k -= buffsize )
TIFFWriteScanline(newImg, (void*)(pbOriImg + k), row);*/
//TIFFClose(newImg);
if( bitsperpixel == 32 )
bytesPerLine = MYWIDTHBYTES(nImgWidth * 24);
else
bytesPerLine = MYWIDTHBYTES(nImgWidth * bitsperpixel);
buffTotalSize = bytesPerLine * height;
nFileSize = buffTotalSize + nPalleteSize * sizeof(RGBQUAD) + sizeof(BITMAPINFOHEADER);
hDIB = (HDIB)GlobalAlloc(GHND, nFileSize);
if( hDIB == NULL )
{
delete []pbOriImg;
pbOriImg = NULL;
return hDIB;
}
LPBYTE lpNewDIB = (LPBYTE)GlobalLock(hDIB);
memset( lpNewDIB, 0, nFileSize * sizeof(BYTE));
LPBITMAPINFOHEADER pInfo = (LPBITMAPINFOHEADER) lpNewDIB;
pInfo->biSize = sizeof(BITMAPINFOHEADER);
pInfo->biWidth = nImgWidth;
pInfo->biHeight = height;
pInfo->biCompression = BI_RGB;
pInfo->biClrUsed = 0;
pInfo->biClrImportant = 0;
pInfo->biPlanes = 1;
pInfo->biSizeImage = buffTotalSize;
pInfo->biXPelsPerMeter = 0;
pInfo->biYPelsPerMeter = 0;
if( bitsperpixel == 32 )
pInfo->biBitCount = 24;
else
pInfo->biBitCount = bitsperpixel;
RGBQUAD *pNewRGBQuad = (RGBQUAD *)( lpNewDIB + sizeof(BITMAPINFOHEADER));
if( bitsperpixel == 1 )
{
pNewRGBQuad->rgbRed = pNewRGBQuad->rgbGreen = pNewRGBQuad->rgbBlue = 0;
pNewRGBQuad->rgbReserved = 0;
pNewRGBQuad ++;
pNewRGBQuad->rgbRed = pNewRGBQuad->rgbGreen = pNewRGBQuad->rgbBlue = 255;
pNewRGBQuad->rgbReserved = 0;
}
else
{
for( int i = 0; i < nPalleteSize; i++, pNewRGBQuad++ )
{
pNewRGBQuad->rgbRed = pNewRGBQuad->rgbGreen = pNewRGBQuad->rgbBlue = i;
pNewRGBQuad->rgbReserved = 0;
}
}
BYTE *pbNewImg = lpNewDIB + sizeof(BITMAPINFOHEADER) + nPalleteSize * sizeof(RGBQUAD) ;
if (bitsperpixel == 32)
{
Img32to24(pbOriImg, pbNewImg, nImgWidth, height);
}
else if (bitsperpixel == 24)
{
ReversColors(pbOriImg, pbNewImg, nImgWidth, height);
}
else
{
for( i = 0, k = 0, row = 0; i < height; i++, k += bytesPerLine, row += buffsize )
{
memcpy(pbNewImg + k, pbOriImg + row, buffsize * sizeof(BYTE));
}
}
if( pbOriImg )
delete []pbOriImg;
pbOriImg = NULL;
return hDIB;
}
void CArdpsImg::Img32to24(BYTE *pbImg32, BYTE *pbImg24, int nWidth, int nHeight)
{
if( pbImg32 == NULL || pbImg24 == NULL )
return;
int i, j, m, n;
LONG nBytesLine24 = MYWIDTHBYTES(nWidth * 24);
BYTE *pbIn = pbImg32;
BYTE *pbOut = pbImg24;
for( i = 0, m = 0, n = 0; i < nHeight; i++, m += nWidth * 4, n += nBytesLine24 )
{
pbIn = pbImg32 + m;
pbOut = pbImg24 + n;
for( j = 0; j < nWidth; j++ )
{
*pbOut = *(pbIn + 2);
*(pbOut + 1) = *(pbIn + 1);
*(pbOut + 2) = *(pbIn);
pbIn += 4;
pbOut += 3;
}
}
}
void CArdpsImg::ReversColors(BYTE*pbIn, BYTE *pbOut, int nWidth, int nHeight)
{
if( pbIn == NULL || pbOut == NULL )
return;
int i, j,n, m;
LONG nBytesLine24 = MYWIDTHBYTES(nWidth * 24);
BYTE *ptmp = pbIn;
BYTE *ptmp2 = pbOut;
for( i = 0, n = 0, m = 0; i < nHeight; i++, n += nBytesLine24, m += nWidth * 3 )
{
ptmp = pbIn + m;
ptmp2 = pbOut + n;
for( j = 0; j < nWidth; j++ )
{
*ptmp2 = *(ptmp + 2);
*(ptmp2 + 1) = *(ptmp + 1);
*(ptmp2 + 2) = *(ptmp);
ptmp2 += 3;
ptmp += 3;
}
}
}
void CArdpsImg::ReversColors(BYTE*pbIn, int nWidth, int nHeight)
{
if( pbIn == NULL )
return;
int i, j, m;
LONG nBytesLine24 = MYWIDTHBYTES(nWidth * 24);
BYTE *ptmp = pbIn;
BYTE bValue = 0;
for( i = 0, m = 0; i < nHeight; i++, m += nBytesLine24 )
{
ptmp = pbIn + m;
for( j = 0; j < nWidth; j++ )
{
bValue = *(ptmp + 2);
*(ptmp + 2) = *(ptmp);
*ptmp = bValue;
ptmp += 3;
}
}
}
bool CArdpsImg::SaveTiff(char *szImgFileName)
{
if( szImgFileName == NULL )
return false;
LPBYTE lpDIB = (LPBYTE) GlobalLock(m_hDib);
if( lpDIB == NULL )
return false;
LPBYTE lpBinImg = FindDIBBits(lpDIB);
if( !lpBinImg )
{
GlobalUnlock(m_hDib);
return false;
}
uint16 samplesperpixel, bitspersample, photometric, compression;
LONG nImgHei = GetHeight();
LONG nImgWid = GetWidth();
WORD nBitCnt = DIBBitCount(lpDIB);
if( nBitCnt == 1)
{
samplesperpixel = 1;
bitspersample = 1;
photometric = PHOTOMETRIC_MINISBLACK;
compression = COMPRESSION_CCITTFAX4;
ReversBits(lpBinImg, nImgWid, nImgHei, nBitCnt);
}
else if (nBitCnt == 8)
{
samplesperpixel = 1;
bitspersample = 8;
photometric = 1;
compression = COMPRESSION_LZW;
}
else if (nBitCnt == 24)
{
samplesperpixel = 3;
bitspersample = 8;
photometric = 2;
compression = COMPRESSION_JPEG;
//compression = COMPRESSION_DEFLATE;
ReversColors(lpBinImg, nImgWid, nImgHei);
}
else
{
GlobalUnlock(m_hDib);
return false;
}
TIFF * newImg = TIFFOpen(szImgFileName, "w");
if( newImg == NULL )
{
GlobalUnlock(m_hDib);
return false;
}
TIFFSetField(newImg, TIFFTAG_IMAGELENGTH, nImgHei);
TIFFSetField(newImg, TIFFTAG_IMAGEWIDTH, nImgWid);
TIFFSetField(newImg, TIFFTAG_SAMPLESPERPIXEL, samplesperpixel);
TIFFSetField(newImg, TIFFTAG_BITSPERSAMPLE,bitspersample);
TIFFSetField(newImg, TIFFTAG_PHOTOMETRIC, photometric);
//if(nBitCnt != 24 ) 只能由程序读取,去掉该注释可以被通用程序读取,压缩比变小。
TIFFSetField(newImg, TIFFTAG_COMPRESSION, compression);
TIFFSetField(newImg, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
uint32 row, buffsize, k;
buffsize = MYWIDTHBYTES(nImgWid * bitspersample * samplesperpixel );
for (row = 0 , k = (nImgHei - 1) * buffsize; row < nImgHei; row++ , k -= buffsize )
TIFFWriteScanline(newImg, (void*)(lpBinImg + k), row, 0);
TIFFClose(newImg);
GlobalUnlock(m_hDib);
return true;
}
void CArdpsImg::ReversBits(BYTE *pbIn, int nWidth, int nHeight, DWORD nBitCnt)
{
int nBytesPerLine = MYWIDTHBYTES(nBitCnt * nWidth );
BYTE *ptmp = pbIn;
for( int i = 0; i < nBytesPerLine * nHeight; i++, ptmp++ )
{
*ptmp = 255- (*ptmp);
}
}
bool CArdpsImg::SaveGrayDIB()
{
LPBITMAPINFOHEADER lpDIBHdr = (LPBITMAPINFOHEADER)GlobalLock(m_hDib);
//for color image
LONG nImgHei = GetHeight();
LONG nImgWid = GetWidth();
//for gray image
LONG nGrayBytesPerLine = MYWIDTHBYTES( nImgWid << 3 );
LONG nGrayImgSize = nGrayBytesPerLine * nImgHei;
LONG nFileSize = nGrayImgSize + lpDIBHdr->biSize + 256 * sizeof(RGBQUAD);
//allocate memory for gray image
LPBYTE lpNewDIB = new BYTE[nFileSize];
if( !lpNewDIB )
return false;
memset(lpNewDIB, 0, nFileSize*sizeof(BYTE));
LPBITMAPINFOHEADER lpNewDIBHdr = (LPBITMAPINFOHEADER)lpNewDIB;
memcpy(lpNewDIBHdr, lpDIBHdr, sizeof(BITMAPINFOHEADER));
GlobalUnlock(m_hDib);
lpNewDIBHdr->biBitCount = 8;
lpNewDIBHdr->biCompression = BI_RGB;
lpNewDIBHdr->biSizeImage = nGrayImgSize;
lpNewDIBHdr->biClrUsed = 256;
lpNewDIBHdr->biXPelsPerMeter = 2952;
lpNewDIBHdr->biYPelsPerMeter = 2952;
//create RGBQUARD
RGBQUAD *pNewRGBQuad = (RGBQUAD*)(lpNewDIB +sizeof(BITMAPINFOHEADER));
memset(pNewRGBQuad, 0, 256*sizeof(RGBQUAD));
for( int i = 0; i < 256; ++i )
{
pNewRGBQuad->rgbBlue = pNewRGBQuad->rgbRed =
pNewRGBQuad->rgbGreen = i;
pNewRGBQuad++;
}
LPBYTE lpDIB = (LPBYTE)GlobalLock(m_hDib);
LPBYTE lpSrcImg = FindDIBBits(lpDIB);
LPBYTE lpNewImg = lpNewDIB + sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD);
bool bConvert = ConvertBinary2Gray(lpSrcImg, nImgWid, nImgHei, lpNewImg);
GlobalUnlock(m_hDib);
bool bCrate = Create(lpNewDIB);
if( lpNewDIB )
delete []lpNewDIB;
lpNewDIB = NULL;
return true;
}