对比两张图片是不是一样的(点、区域)
原理:读取两张图片相同坐标的RGB像素,将图片的RGB值与参照物图片的RGB值做对比。
相似度= (相同像素/ (icon_width * icon_height) * 100)
相同像素:两张图片的同一坐标的RGB值一样。
图片中坐标与RGB值的映射关系:
假设图片大小:1920* 720、 X坐标、Y坐标;
代码中BMP图片的规范为4通道32bit;
某个点的RGB:首地址+ X * 4 + Y * 1920 * 4
bitmapdf.h:
#define RETURN_SUCCESS 1
#define RETURN_ERROR 0
typedef long LONG;
typedef unsigned char BYTE;
typedef unsigned short WORD;
typedef unsigned long DWORD;
/*Bitmap data structures*/
typedef struct BITMAP
{
DWORD biSize; //bitmap size
LONG biWidth; //bitmap width
LONG biHeight; //bitmap height
WORD biPlanes;
WORD biBitCount; //bit depth
DWORD biCompression;
DWORD biSizeImage;
LONG biXPelsPerMeter; //horizontal resolution
LONG biYPelsPerMeter; //vertical resolution
DWORD biClrUsed;
DWORD biClrImportant;
}BITMAPINFOHEADER;
typedef struct RGB
{
BYTE byR;
BYTE byG;
BYTE byB;
}BITMAPRGB;
typedef enum
{
BM_BLACKSCREEN_PATH = 0, //黑屏位图
BM_LAMPMONITO_PATH = 1, //指示灯监视位图
}BITMAP_FILE_PATH;
#define BM_BLACKSCREEN_PATH_ "/tmp/ScreenShot.bmp"
#define BM_LAMPMONITO_PATH_ "/tmp/LampMonitor.bmp"
#define BM_REFERENCE_PATH_ "/data/LampReference.bmp" //Used as a reference (The indicator light to be monitored must be kept on)
typedef struct
{
int iCoordinate_X;
int iCoordinate_Y;
int iIconWidth;
int iIconHeight;
}StBitmapCfgInfo;
CBitmap.h:
class CBitmap {
public:
CBitmap();
virtual ~CBitmap();
public:
int ReadReferenceBitmap(const char *szFileName);
int ReadCompareBitmap(const char *szFileName);
int GetBitmapRGB2Compare(StBitmapCfgInfo stCfg);
public:
BYTE *m_byBufReference; /*Storage indicator normally displays data*/
BYTE *m_byBufCompare; /*Store images for comparison*/
LONG m_LineByteWidth[2]; /* biWidth * (biBitCount / 8)*/
BITMAPINFOHEADER m_stBitmapReference;
BITMAPINFOHEADER m_stBitmapCompare;
};
CBitmap.cpp
CBitmap::CBitmap() {
// TODO Auto-generated constructor stub
m_byBufReference = NULL;
m_byBufCompare = NULL;
}
CBitmap::~CBitmap() {
// TODO Auto-generated destructor stub
}
int CBitmap::ReadReferenceBitmap(const char *szFileName)
{
FILE *file;
WORD bfh[7];
LONG dpixeladd; //bit depth
if (NULL == (file = fopen(szFileName, "rb")))
{
LOGWAR("open normal bitmap file falied");
return RETURN_ERROR;
}
fread(&bfh, sizeof(WORD), 7, file);
if (bfh[0] != (WORD)(((WORD)'B')|('M'<<8)))
{
LOGWAR("read bitmap head failed");
fclose(file);
return RETURN_ERROR;
}
fread(&m_stBitmapReference, sizeof(BITMAPINFOHEADER), 1, file);
if(m_stBitmapReference.biBitCount < 24)
{
LOGWAR("Bitmap bitdepth does not meet requirements");
fclose(file);
return RETURN_ERROR;
}
/*The number of bytes required for a pixel
* Four bytes represent one pixel*/
dpixeladd = m_stBitmapReference.biBitCount / 8;
m_LineByteWidth[0] = m_stBitmapReference.biWidth * dpixeladd;
if ((m_LineByteWidth[0] % 4) != 0)
{
m_LineByteWidth[0] += 4 - (m_LineByteWidth[0] % 4);
}
if ((m_byBufReference = (BYTE*)malloc(sizeof(BYTE)* m_LineByteWidth[0] * abs(m_stBitmapReference.biHeight))) != NULL)
{
fread(m_byBufReference, m_LineByteWidth[0] * abs(m_stBitmapReference.biHeight), 1, file);
fclose(file);
return RETURN_SUCCESS;
}
fclose(file);
return RETURN_ERROR;
}
int CBitmap::ReadCompareBitmap(const char *szFileName)
{
FILE *file;
WORD bfh[7];
LONG dpixeladd; //bit depth
if (NULL == (file = fopen(szFileName, "rb")))
{
LOGWAR("open normal bitmap file falied");
return RETURN_ERROR;
}
fread(&bfh, sizeof(WORD), 7, file);
if (bfh[0] != (WORD)(((WORD)'B')|('M'<<8)))
{
LOGWAR("read bitmap head failed");
fclose(file);
return RETURN_ERROR;
}
fread(&m_stBitmapCompare, sizeof(BITMAPINFOHEADER), 1, file);
if(m_stBitmapCompare.biBitCount < 24)
{
LOGWAR("Bitmap bitdepth does not meet requirements");
fclose(file);
return RETURN_ERROR;
}
/*The number of bytes required for a pixel
* Four bytes represent one pixel*/
dpixeladd = m_stBitmapCompare.biBitCount / 8;
m_LineByteWidth[1] = m_stBitmapCompare.biWidth * dpixeladd;
if ((m_LineByteWidth[1] % 4) != 0)
{
m_LineByteWidth[1] += 4 - (m_LineByteWidth[1] % 4);
}
if ((m_byBufCompare = (BYTE*)malloc(sizeof(BYTE)* m_LineByteWidth[1] * abs(m_stBitmapCompare.biHeight))) != NULL)
{
fread(m_byBufCompare, m_LineByteWidth[1] * abs(m_stBitmapCompare.biHeight), 1, file);
fclose(file);
return RETURN_SUCCESS;
}
fclose(file);
return RETURN_ERROR;
}
int CBitmap::GetBitmapRGB2Compare(StLampMonitorCfgInfo stLampCfg, int iID)
{
if(stLampCfg.iCoordinate_X < 0
|| stLampCfg.iCoordinate_X > m_stBitmapReference.biWidth
|| stLampCfg.iCoordinate_Y < 0
|| stLampCfg.iCoordinate_Y > abs(m_stBitmapReference.biHeight)
|| stLampCfg.iIconWidth < 0
|| stLampCfg.iIconWidth > m_stBitmapReference.biWidth
|| stLampCfg.iIconHeight < 0
|| stLampCfg.iIconHeight > abs(m_stBitmapReference.biHeight))
{
LOGWAR("Bitmap coordinates are not in range");
return RETURN_ERROR;
}
int iTempX;
int iTempY;
int dpixeladd;
int iTotalPixels;
int iSamePixels = 0;
float iSimilarity;
BYTE *pBufReference;
BYTE *pBufCompare;
BITMAPRGB stRGB[2];
dpixeladd = m_stBitmapReference.biBitCount / 8;
if(dpixeladd != 4)
{
LOGWAR("Invalid bitmap");
return RETURN_ERROR;
}
iTotalPixels = stLampCfg.iIconWidth * stLampCfg.iIconHeight;
for(iTempX = stLampCfg.iCoordinate_X; iTempX < stLampCfg.iCoordinate_X + stLampCfg.iIconWidth; iTempX++)
{
for(iTempY = stLampCfg.iCoordinate_Y; iTempY < stLampCfg.iCoordinate_Y + stLampCfg.iIconHeight; iTempY++)
{
/*坐标与像素的映射关系:指针首地址 + iTempX * 4 + iTempY * 1920 * 4
iTempX:要比较像素的x坐标
dpixeladd: 32 / 8, 一个像素占用4个字节 B G R A
iTempY * m_LineByteWidth: 1920 * 4 * Y (列 * 行的指针偏移) */
/* The indicator normally displays */
pBufReference = m_byBufReference + iTempX * dpixeladd + iTempY * m_LineByteWidth[0];
stRGB[0].byB = *pBufReference;
stRGB[0].byG = *(pBufReference + 1);
stRGB[0].byR = *(pBufReference + 2);
/*Whether the indicator is displayed */
pBufCompare = m_byBufCompare + iTempX * dpixeladd + iTempY * m_LineByteWidth[1];
stRGB[1].byB = *pBufCompare;
stRGB[1].byG = *(pBufCompare + 1);
stRGB[1].byR = *(pBufCompare + 2);
/*printf("stRGB[0].byB = %d stRGB[1].byB = %d, stRGB[0].byG = %d stRGB[1].byG = %d, stRGB[0].byR = %d stRGB[1].byR = %d \n",
stRGB[0].byB,
stRGB[1].byB,
stRGB[0].byG,
stRGB[1].byG,
stRGB[0].byR,
stRGB[1].byR);*/
/* RGB compare */
if((stRGB[0].byB == stRGB[1].byB) && (stRGB[0].byG == stRGB[1].byG) && (stRGB[0].byR == stRGB[1].byR))
{
iSamePixels++;
}
}
}
/*If the similarity is greater than 80%, the indicator is normally displayed */
iSimilarity = ((float)iSamePixels / (float)iTotalPixels) * 100;
LOGDBG("iTotalPixels = %d, iSamePixels = %d, iSimilarity = %f",iTotalPixels, iSamePixels, iSimilarity);
printf("iTotalPixels = %d, iSamePixels = %d, iSimilarity = %f \n",iTotalPixels, iSamePixels, iSimilarity);
if(iSimilarity < 90)
{
LOGERR("error: Indicator light is not showing: %d", iID);
}
free(m_byBufReference), m_byBufReference = NULL;
free(m_byBufCompare), m_byBufCompare = NULL;
return RETURN_SUCCESS;
}
main.c:
int main(int argc, char *argv[])
{
CBitmap objBitmap;
StBitmapCfgInfo objStMap;
//对比图片的某个矩形区域
objStMap.iCoordinate_X = 10;
objStMap.iCoordinate_Y = 10;
objStMap.iIconWidth= 50;
objStMap.iIconHeight= 50;
if(!objBitmap.ReadReferenceBitmap(BM_REFERENCE_PATH_))
{
LOGWAR ("ReadReferenceBitmap error. ");
return;
}
if(!objBitmap.ReadCompareBitmap(BM_LAMPMONITO_PATH_))
{
LOGWAR ("ReadCompareBitmap error. ");
return;
}
objBitmap.GetBitmapRGB2Compare(objStMap);
}