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

图像相减操作对于入门的小伙伴来说很简单原理如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;
	
}

 

你可能感兴趣的:(c++,opencv,图像识别)