2019-07-10

                                                                   对比两张图片是不是一样的(点、区域)

原理:读取两张图片相同坐标的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);

}

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,684评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,143评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,214评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,788评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,796评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,665评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,027评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,679评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,346评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,664评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,766评论 1 331
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,412评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,015评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,974评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,073评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,501评论 2 343

推荐阅读更多精彩内容