Opencv中Mat常见扩展操作

直接上源码,首先是头文件:


/* ******* OpencvUser.h **********
********* opencv常用操作函数声明 ********** */

/* author: autumoon */

#pragma once

#include "opencv.hpp"

class COpencvUser
{
public:

public:
	COpencvUser(){};
	~COpencvUser(){};

public:
	//nMergeMethod 0自动 1垂直 2水平
	static cv::Mat MergeMat(cv::Mat mFirst, cv::Mat mSecond, const int& nMergeMethod = 0);
	//将Buffer转换为Mat(bTrans2BGR为true时,假设输入为灰度或者RGB(A))
	static cv::Mat TransBufferToMat(unsigned char* pBuffer, int nWidth, int nHeight, int nBandNum, int nBPB, bool bTrans2BGR = false, bool bYReverse = true);

	//取得平均值
	static cv::Scalar GetAvgValue(const cv::Mat& mSrc);

	//自动阈值Canny
	static int AutoCanny(cv::Mat mSrcGray, cv::Mat& mEdgesGray, double& threshold1, double& threshold2, int apertureSize = 3, bool L2gradient = false);
	//带遮罩的直方图均衡化
	static int EqualizeHistMask(cv::Mat& mImageBGR, cv::Mat mMaskGray);
	//nPos小于0腐蚀,大于0膨胀
	static int ErodeDilate(cv::Mat mSrc, cv::Mat& mDst, int nPos);
	//nPos小于0开运算,大于0闭运算
	static int OpenClose(cv::Mat mSrc, cv::Mat& mDst, int nPos);
	//将Mat转换为Buffer,注意释放*ppBuffer
	static int TransMatToBuffer(cv::Mat mSrc, unsigned char** ppBuffer, int& nWidth, int& nHeight, int& nBandNum, int& nBPB, int nAlign = -1, bool bYReverse = false);
	//使得roi区域合法
	static int ValidRect(cv::Rect& roi, const int& nWidth, const int& nHeight);

private:
	//根据直方图自动确定高低阈值
	static int AdaptiveFindThreshold(cv::Mat dx, cv::Mat dy, double& low, double& high);
	static int EqualizeHistGray(cv::Mat& mImgGray, cv::Mat& mMaskGray);
};

然后是cpp文件:

/* ******* OpencvUser.cpp **********
********* opencv常用操作函数实现 ********** */

/* author: autumoon */

#include "OpencvUser.h"

cv::Mat COpencvUser::MergeMat(cv::Mat mFirst, cv::Mat mSecond, const int& nMergeMethod /*= 0*/)
{
	if (mFirst.type() != mSecond.type())
	{
		return mSecond;
	}

	//分界线的宽度
	const int nGapPixs = 2;
	//首先决定是水平方向合并,还是垂直方向合并
	int nTmpWidth = mFirst.cols + mSecond.cols + nGapPixs;
	int nTmpHeight = mFirst.rows + mSecond.rows + nGapPixs;

	//判断是否水平方向合并
	bool bHorizontal = nMergeMethod == 0 || nMergeMethod == 2;
	if (nMergeMethod == 0)
	{
		//根据宽高来决定合并方式
		bHorizontal = bHorizontal && nTmpHeight > nTmpWidth;
	}

	if (bHorizontal)
	{
		//水平方向合并
		int nNewWidth = nTmpWidth;
		int nNewHeight = MAX(mFirst.rows, mSecond.rows);
		cv::Mat mDst = cv::Mat::zeros(cv::Size(nNewWidth, nNewHeight), mFirst.type());

		//加入第一张影像
		int nOffsetY = 0;
		if (mFirst.rows < nNewHeight)
		{
			nOffsetY = (nNewHeight - mFirst.rows) / 2;
		}
		cv::Mat mDstFirst = mDst(cv::Rect(0, nOffsetY, mFirst.cols, mFirst.rows));
		mFirst.copyTo(mDstFirst);

		//加入第二张影像
		nOffsetY = 0;
		if (mSecond.rows < nNewHeight)
		{
			nOffsetY = (nNewHeight - mSecond.rows) / 2;
		}
		cv::Mat mDstSecond= mDst(cv::Rect(mFirst.cols + nGapPixs, nOffsetY, mSecond.cols, mSecond.rows));
		mSecond.copyTo(mDstSecond);

		return mDst;
	}
	else
	{
		//垂直方向合并
		int nNewWidth = MAX(mFirst.cols, mSecond.cols);
		int nNewHeight = nTmpHeight;
		cv::Mat mDst = cv::Mat::zeros(cv::Size(nNewWidth, nNewHeight), mFirst.type());

		//加入第一张影像
		int nOffsetX = 0;
		if (mFirst.cols < nNewWidth)
		{
			nOffsetX = (nNewWidth - mFirst.cols) / 2;
		}
		cv::Mat mDstFirst = mDst(cv::Rect(nOffsetX, 0, mFirst.cols, mFirst.rows));
		mFirst.copyTo(mDstFirst);

		//加入第二张影像
		nOffsetX = 0;
		if (mSecond.cols < nNewWidth)
		{
			nOffsetX = (nNewWidth - mSecond.cols) / 2;
		}
		cv::Mat mDstSecond= mDst(cv::Rect(nOffsetX, mFirst.rows + nGapPixs, mSecond.cols, mSecond.rows));
		mSecond.copyTo(mDstSecond);

		return mDst;
	}
}

cv::Mat COpencvUser::TransBufferToMat(unsigned char* pBuffer, int nWidth, int nHeight, int nBandNum, int nBPB, bool bTrans2BGR /*= false*/, bool bYReverse /*= true*/)
{
	cv::Mat mDst;
	if (nBandNum == 4)
	{
		if (nBPB == 1)
		{
			mDst = cv::Mat::zeros(cv::Size(nWidth, nHeight), CV_8UC4);
		}
		else if (nBPB == 2)
		{
			mDst = cv::Mat::zeros(cv::Size(nWidth, nHeight), CV_16UC4);
		}
	}
	else if (nBandNum == 3)
	{
		if (nBPB == 1)
		{
			mDst = cv::Mat::zeros(cv::Size(nWidth, nHeight), CV_8UC3);
		}
		else if (nBPB == 2)
		{
			mDst = cv::Mat::zeros(cv::Size(nWidth, nHeight), CV_16UC3);
		}
	}
	else if (nBandNum == 1)
	{
		if (nBPB == 1)
		{
			mDst = cv::Mat::zeros(cv::Size(nWidth, nHeight), CV_8UC1);
		}
		else if (nBPB == 2)
		{
			mDst = cv::Mat::zeros(cv::Size(nWidth, nHeight), CV_16UC1);
		}
	}

	if (bYReverse)
	{
		for (int j = 0; j < nHeight; ++j)
		{
			unsigned char* data = mDst.ptr<unsigned char>(j);
			unsigned char* pSubBuffer = pBuffer + (nHeight - 1 - j) * nWidth  * nBandNum * nBPB;
			memcpy(data, pSubBuffer, nWidth * nBandNum * nBPB);
		}
	}
	else
	{
		for (int j = 0; j < nHeight; ++j)
		{
			unsigned char* data = mDst.ptr<unsigned char>(j);
			unsigned char* pSubBuffer = pBuffer + (j) * nWidth  * nBandNum * nBPB;
			memcpy(data, pSubBuffer, nWidth * nBandNum * nBPB);
		}
	}

	if (bTrans2BGR)
	{
		if (nBandNum == 1)
		{
			cv::cvtColor(mDst, mDst, CV_GRAY2BGR);
		}
		else if (nBandNum == 3)
		{
			cv::cvtColor(mDst, mDst, CV_RGB2BGR);
		}
		else if (nBandNum == 4)
		{
			cv::cvtColor(mDst, mDst, CV_RGBA2BGR);
		}
	}

	return mDst;
}


cv::Scalar COpencvUser::GetAvgValue(const cv::Mat& mSrc)
{
	IplImage gray = mSrc;

	return cvAvg(&gray);
}

int COpencvUser::AutoCanny(cv::Mat mSrcGray, cv::Mat& mEdgesGray, double& threshold1, double& threshold2, int apertureSize /*= 3*/, bool L2gradient /*= false*/)
{
	if (mSrcGray.cols <= 0 || mSrcGray.rows <= 0)
	{
		//默认值
		threshold1 = 100.0;
		threshold2 = 200.0;
		return -1;
	}

	const int cn = mSrcGray.channels();
	cv::Mat dx(mSrcGray.rows, mSrcGray.cols, CV_16SC(cn));
	cv::Mat dy(mSrcGray.rows, mSrcGray.cols, CV_16SC(cn));

	Sobel(mSrcGray, dx, CV_16S, 1, 0, apertureSize, 1, 0, cv::BORDER_REPLICATE);
	Sobel(mSrcGray, dy, CV_16S, 0, 1, apertureSize, 1, 0, cv::BORDER_REPLICATE);

	if (threshold1 < 0.0 || threshold2 < 0.0)
	{
		AdaptiveFindThreshold(dx, dy, threshold1, threshold2);
		std::cout << "auto thresh:  threshold1 = " << threshold1 << "  threshold2 = "<< threshold2 << std::endl;
	}

	cv::Canny(mSrcGray, mEdgesGray, threshold1, threshold2, apertureSize, L2gradient);

	return 0;
}

int COpencvUser::EqualizeHistMask(cv::Mat& mImageBGR, cv::Mat mMaskGray)
{
	if (mImageBGR.depth() != CV_8U)
	{
		//只处理8位
		return -1;
	}

	size_t width = mImageBGR.cols;
	size_t height = mImageBGR.rows;
	std::vector<cv::Mat> vm;
	cv::split(mImageBGR, vm);

	size_t c = MIN(3, vm.size());

	for (size_t i = 0; i < c; ++i)
	{
		EqualizeHistGray(vm[i], mMaskGray);
	}

	cv::merge(vm, mImageBGR);

	return 0;
}

int COpencvUser::ErodeDilate(cv::Mat mSrc, cv::Mat& mDst, int nPos)
{
	int an = abs(nPos);
	cv::Mat element = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(an * 2 + 1, an * 2 + 1), cv::Point(an, an));

	if( nPos < 0 )
		cv::erode(mSrc, mDst, element);
	else
		cv::dilate(mSrc, mDst, element);

	return 0;
}

int COpencvUser::OpenClose(cv::Mat mSrc, cv::Mat& mDst, int nPos)
{
	int an = abs(nPos);
	cv::Mat element = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(an * 2 + 1, an * 2 + 1), cv::Point(an, an));

	if( nPos < 0 )
		cv::morphologyEx(mSrc, mDst, CV_MOP_OPEN, element);
	else
		cv::morphologyEx(mSrc, mDst, CV_MOP_CLOSE, element);

	return 0;
}

int COpencvUser::TransMatToBuffer(cv::Mat mSrc, unsigned char** ppBuffer, int& nWidth, int& nHeight, int& nBandNum, int& nBPB, int nAlign /*= -1*/, bool bYReverse /*= false*/)
{
	if (*ppBuffer)
	{
		delete[] * ppBuffer;
		*ppBuffer = nullptr;
	}

	nWidth = mSrc.cols;

	if (nAlign > 0)
	{
		nWidth = ((nWidth + nAlign - 1) / nAlign) * nAlign;
	}

	nHeight = mSrc.rows;
	nBandNum = mSrc.channels();
	nBPB = (mSrc.depth() >> 1) + 1;

	size_t nMemSize = nWidth * nHeight * nBandNum * nBPB;
	//这样可以改变外部*pBuffer的值
	*ppBuffer = new uchar[nMemSize];
	memset(*ppBuffer, 0, nMemSize);

	if (bYReverse)
	{
		for (int j = 0; j < nHeight; ++j)
		{
			unsigned char* data = mSrc.ptr<unsigned char>(nHeight - 1 - j);
			unsigned char* pSubBuffer = *ppBuffer + (j)* nWidth  * nBandNum * nBPB;
			memcpy(pSubBuffer, data, nWidth * nBandNum * nBPB);
		}
	}
	else
	{
		for (int j = 0; j < nHeight; ++j)
		{
			unsigned char* data = mSrc.ptr<unsigned char>(j);
			unsigned char* pSubBuffer = *ppBuffer + (j)* nWidth  * nBandNum * nBPB;
			memcpy(pSubBuffer, data, nWidth * nBandNum * nBPB);
		}
	}

	return 0;
}

int COpencvUser::ValidRect(cv::Rect& roi, const int& nWidth, const int& nHeight)
{
	if (roi.x < 0 || roi.x > nWidth - 1)
	{
		roi.x = 0;
	}

	if (roi.x + roi.width > nWidth)
	{
		roi.width = nWidth - roi.x;
	}

	if (roi.y < 0 || roi.y > nHeight - 1)
	{
		roi.y = 0;
	}

	if (roi.y + roi.height > nHeight)
	{
		roi.height = nHeight - roi.y;
	}

	return 0;
}

int COpencvUser::AdaptiveFindThreshold(cv::Mat dx, cv::Mat dy, double& low, double& high)
{
	CvSize size;
	IplImage *imge = nullptr;
	int i = 0,j = 0;
	CvHistogram *hist;
	int hist_size = 255;
	float range_0[]={0,256};
	float* ranges[] = { range_0 };
	double  PercentOfPixelsNotEdges = 0.7;
	size = dx.size();
	imge = cvCreateImage(size, IPL_DEPTH_32F, 1);

	// 计算边缘的强度, 并存于图像中
	float maxv = 0;
	for(i = 0; i < size.height; i++ )
	{
		const short* _dx = dx.ptr<short>(i);	//(short*)(dx->data.ptr + dx->step*i);
		const short* _dy = dy.ptr<short>(i);	//(short*)(dy->data.ptr + dy->step*i);
		float* _image = (float *)(imge->imageData + imge->widthStep*i);
		for(j = 0; j < size.width; j++)
		{
			_image[j] = (float)(abs(_dx[j]) + abs(_dy[j]));
			maxv = MAX(maxv, _image[j]);
		}
	}

	// 计算直方图
	range_0[1] = maxv;
	hist_size = (int)(hist_size > maxv ? maxv:hist_size);
	hist = cvCreateHist(1, &hist_size, CV_HIST_ARRAY, ranges, 1);
	cvCalcHist( &imge, hist, 0, NULL );
	int total = (int)(size.height * size.width * PercentOfPixelsNotEdges);
	float sum=0;
	int icount = hist->mat.dim[0].size;
	float *h = (float*)cvPtr1D( hist->bins, 0 );
	for(i = 0; i < icount; i++)
	{
		sum += h[i];
		if( sum > total )
			break; 
	}

	// 计算高低门限
	high = (i+1) * maxv / hist_size ;
	low = high * 0.4;

	cvReleaseImage( &imge );
	cvReleaseHist(&hist);

	return 0;
}

int COpencvUser::EqualizeHistGray(cv::Mat& mImageGray, cv::Mat& mMaskGray)
{
	if (mImageGray.depth() != CV_8U)
	{
		//只处理8位单通道
		return -1;
	}

	if (mImageGray.size() != mMaskGray.size())
	{
		//此时mask无效
		cv::equalizeHist(mImageGray, mImageGray);

		return 0;
	}

	size_t width = mImageGray.cols;
	size_t height = mImageGray.rows;

	// 灰度映射表
	uchar map[256];
	long lCounts[256];
	memset(lCounts, 0, sizeof(long) * 256);
	size_t nPixCount = 0;

	// 计算各灰度值个数
	for (int j = 0; j < height; ++j)
	{
		uchar* data = mImageGray.ptr<uchar>(j);
		uchar* mask = mMaskGray.ptr<uchar>(j);
		for (size_t i = 0; i < width; ++i)
		{
			if (mask[i])
			{
				uchar x = data[i];
				lCounts[x]++;
				nPixCount++;
			}
		}
	}

	// 保存运算中的临时值
	for (size_t i = 1; i < 256; i++)
	{
		lCounts[i] = lCounts[i - 1] + lCounts[i] ;
		map[i] = (uchar)(lCounts[i] * 255.0f / nPixCount);
	}

	// 变换后的值直接在映射表中查找
	for (int j = 0; j < height; ++j)
	{
		uchar* data = mImageGray.ptr<uchar>(j);
		uchar* mask = mMaskGray.ptr<uchar>(j);
		for (size_t i = 0; i < width; ++i)
		{
			if (mask[i])
			{
				data[i] = map[data[i]];
			}
		}
	}

	return 0;
}

猜你喜欢

转载自blog.csdn.net/autumoonchina/article/details/84062840