实现图像相减的操作 opencv 、halcon、 c++底层实现以及sse加速

    技术2022-07-11  124

    图像相减操作对于入门的小伙伴来说很简单原理如halcon给的算子解释手册一样:

     其中 g1和g2是输入图片对应的像素,mult则是比例系数

    对于halcon来说,实现图像相减使用的算子就是  abs_diff_image

    对于opencv来说可以自己实现访问像素也可以用函数实现:

    #include "cv.h" #include "highgui.h" #include "cxcore.h" int main(int argc,char** argv) {cvNamedWindow("a",0); IplImage* img=cvLoadImage("11.jpg"); cvShowImage("a",img); cvNamedWindow("b",0); IplImage* img1=cvLoadImage("12.jpg"); cvShowImage("b",img1); IplImage* diff=cvCreateImage(cvGetSize(img),img->depth,img->nChannels); cvAbsDiff(img,img1,diff); cvNamedWindow("r",0); cvShowImage("r",diff); while (1) {if (cvWaitKey(100)==27) break; } cvDestroyWindow("a"); cvDestroyWindow("b"); cvReleaseImage(&img); cvReleaseImage(&img1); cvReleaseImage(&diff); return 0; }

    最近在研究图像的底层实现c++的图像实现如下:

    void diffImage(unsigned char* src, unsigned char* src1, uint32_t nW, uint32_t nH, uint32_t k, unsigned char* dst) { int diff_value; //-------开始像素遍历---------------- for (int i = 0; i < nH ; i++) { for (int j = 0; j < nW ; j++) { diff_value = abs(src1[i*nW + j] - src[i*nW + j])*k; if (diff_value > 255) diff_value = 255; dst[i*nW + j] = diff_value; } } }

     重点来了,sse加速版本的操作,循环跑了1000次,2000w像素的图像,6.8ms,测得比halcon(10ms以上)快。(这里有个骚操作)

    void diffImage_SSE(unsigned char* src, unsigned char* src1, uint32_t Width, uint32_t Height, uint32_t channle, uint32_t k, unsigned char* dst) { __m128i mult = _mm_set1_epi16(k); __m128i Zero = _mm_set1_epi8(0); __m128i m127 = _mm_set1_epi8(127); int BlockSize = 16; //一次来十六个 int Block = Width*Height*channle/BlockSize; for (int i = 0; i < BlockSize*Block; i += BlockSize) { if (i == 1408) { int k = 0; } //先load进两张图片的数据 __m128i inputdataOne = _mm_loadu_si128((__m128i*)(src+i)); __m128i inputdataTwo = _mm_loadu_si128((__m128i*)(src1 + i)); //做无符号的减法先(a-b)然后(b-a)然后相加,其实就是做了abs(a-b)操作 __m128i imagedataDst1 =_mm_subs_epu8(inputdataOne, inputdataTwo); __m128i imagedataDst2 = _mm_subs_epu8(inputdataTwo, inputdataOne); __m128i imagedataDst = _mm_adds_epu8(imagedataDst1, imagedataDst2); //unpack高低位 __m128i highDst = _mm_unpackhi_epi8(imagedataDst, Zero); __m128i lowhDst = _mm_unpacklo_epi8(imagedataDst, Zero); //做完乘法取低16位就可以 __m128i highDst1 = _mm_mullo_epi16(highDst, mult); __m128i lowhDst1 = _mm_mullo_epi16(lowhDst, mult); //用pack将高低位链接,注意第一个参数个低位第二个参数是高位 __m128i imagedata = _mm_packs_epi16(lowhDst1, highDst1); _mm_storeu_si128((__m128i*)(dst + i), imagedataDst); } for (int j = BlockSize*Block; j < Width*Height*channle; j++) { dst[j] = IM_ClampToByte((src[j] - src1[j])*k); } } inline unsigned char IM_ClampToByte(int Value) { if (Value < 0) return 0; else if (Value > 255) return 255; else return (unsigned char)Value; }

     

    Processed: 0.015, SQL: 9