opencv C++常用算子封装

简介:封装一些opencv C++的算子,达到一种开箱即用的效果,在算法预研阶段能快速出结果,可以当做调用示例,也可直接使用避免每次都重复编写。

在这里插入图片描述

  • imageProcess.h

#pragma once
#include "opencv.hpp"

namespace cvbag
{
	bool isImageEmpty(const cv::Mat &image, const std::string functionName);

	int getAllImagePath( std::string folder, std::vector<cv::String> &imagePathList, bool flg=false);

	int showImage(const cv::Mat &image, const std::string winName = "img", const int waitKeyMode = 0, const int destroyMode = 0);

	int gaussBlur(const cv::Mat &image, cv::Mat &dst, const int ksize = 5, double sigma = 1.0);

	int sobel_x(const cv::Mat &image, cv::Mat &dst, const int ksize = 3);

	int sobel_y(const cv::Mat &image, cv::Mat &dst, const int ksize = 3);

	int sobel_xy(const cv::Mat &image, cv::Mat &dst, const int ksize = 3);

	int canny(const cv::Mat &image, cv::Mat &dst, const int low = 100, const int heigh = 200);

	int otsu(const cv::Mat &image, cv::Mat &dst);

	int threshold(const cv::Mat &image, cv::Mat &dst, const int th = 128, const int mode = 0, const int maxval = 255);

	int adaptiveThreshold(const cv::Mat &image, cv::Mat &dst, int blockSize = 11, double C = 15, double maxval = 255,
		int adaptiveMethod = cv::ADAPTIVE_THRESH_MEAN_C, int thresholdType = cv::THRESH_BINARY_INV);

	int  findContours(const cv::Mat &binaryImage, std::vector<std::vector<cv::Point>> &contours, int topologyMode = 1, int contoursType = 1);

	int drawContours(cv::Mat &image, const std::vector<std::vector<cv::Point>> &contours, int contoursIdx = -1, int b = 0, int g = 0, int r = 255);

	int dilate(const cv::Mat &binaryImage, cv::Mat &dst, const int ksize = 3, const int kernelMode = 0);

	int erode(const cv::Mat &binaryImage, cv::Mat &dst, const int ksize = 3, const int kernelMode = 0);

	int open(const cv::Mat &binaryImage, cv::Mat &dst, const int ksize = 3, const int kernelMode = 0);

	int close(const cv::Mat &binaryImage, cv::Mat &dst, const int ksize = 3, const int kernelMode = 0);

	//use the table to transform the pixels 
	int gammaTransform(const cv::Mat &image, cv::Mat &dst, const int  table[]);
	//if the input image's format  is 3 channels then use below method to transform the pixels
	int gammaTransform_threeChannels(const cv::Mat &image, cv::Mat &dst, const int table[]);
	//a[i] = int(pow(i / 255.0, gamma) *255.0);
	int getGammaTable(const double gamma, int *a, const int num = 256);
	//gamma API
	int gamma(const cv::Mat &image, cv::Mat &dst, const double gamma = 1.0);

	//gamma piecewise linear function transform
	int getGammaTable_piecewiseLinear(int *a, const int src1, const int dst1 , const int src2 , const int dst2 );
	//gamma_picewiseLinear 
	/*
		f(x) = (dst1 / src1) * x; if x<src1
		  = [(dst2 - dst1) / (src2 - src1)] * (x - src1) + dst1; if x>=src1 and x<src2;
		  = [(255 - dst2) / (255 - src2)] * (x - src2) + dst2; if x>=src2;
	*/
	int gamma_picewiseLinear(const cv::Mat &image, cv::Mat &dst,
		const int src1 = 80, const int dst1 = 60, const int src2 = 160, const int dst2 = 180);
	
};
  • imageProcess.cpp

#include "imageProcess.h"

bool cvbag::isImageEmpty(const cv::Mat &image, const std::string functionName)
{
	if (image.empty())
	{
		std::cout << "ERROR \t in cvbag::"<<functionName<<" ,the input image is empty!\n";
		return true;
	}

	return false;
}

int cvbag::getAllImagePath(std::string folder, std::vector<cv::String> &imagePathList, bool flg)
{
	cv::glob(folder, imagePathList, flg);
	return 0;
}

int cvbag::showImage(const cv::Mat &image, const std::string winName, const int waitKeyMode, const int destroyMode)
{
	if (cvbag::isImageEmpty(image,"showImage"))
	{
		return - 1;
	}

	cv::namedWindow(winName, CV_WINDOW_NORMAL);
	cv::imshow(winName, image);
	cv::waitKey(waitKeyMode);
	if (destroyMode == 1)
	{
		cv::destroyWindow(winName);
	}

	return 0;
}

int cvbag::gaussBlur(const cv::Mat &image, cv::Mat &dst, const int ksize, double sigma)
{
	if (cvbag::isImageEmpty(image, "gaussBlur"))
	{
		return -1;
	}
	cv::GaussianBlur(image, dst, cv::Size(ksize, ksize), sigma);
	return 0;
}

int cvbag::sobel_x(const cv::Mat &image, cv::Mat &dst, const int ksize)
{
	if (cvbag::isImageEmpty(image, "sobel_x"))
	{
		return -1;
	}

	cv::Sobel(image, dst, CV_64F, 1, 0, ksize);
	return 0;
}

int cvbag::sobel_y(const cv::Mat &image, cv::Mat &dst, const int ksize)
{
	if (cvbag::isImageEmpty(image, "sobel_y"))
	{
		return -1;
	}

	cv::Sobel(image, dst, CV_64F, 0, 1, ksize);
	return 0;
}

int cvbag::sobel_xy(const cv::Mat &image, cv::Mat &dst, const int ksize)
{
	if (cvbag::isImageEmpty(image, "sobel_xy"))
	{
		return -1;
	}
	cv::Mat sobel_x, sobel_y;
	cvbag::sobel_x(image, sobel_x, ksize);
	cvbag::sobel_y(image, sobel_y, ksize);
	cv::addWeighted(sobel_x, 0.5, sobel_y, 0.5, 0, dst);
	return 0;
}

int cvbag::canny(const cv::Mat &image, cv::Mat &dst, const int low, const int heigh)
{
	if (cvbag::isImageEmpty(image, "canny")) return -1;

	cv::Canny(image, dst, low, heigh);
	return 0;
}

int cvbag::otsu(const cv::Mat &image, cv::Mat &dst)
{
	if (cvbag::isImageEmpty(image, "adaptiveThreshold")) return -1;
	if (image.channels() == 3) cv::cvtColor(image, dst, cv::COLOR_BGR2GRAY);
	cv::threshold(dst, dst, 0, 255, 8);
	return 0;
}

int cvbag::threshold(const cv::Mat &image, cv::Mat &dst, const int th , const int mode, const int maxval)
{
	/*
	enum ThresholdTypes {
	THRESH_BINARY     = 0, //!< \f[\texttt{dst} (x,y) =  \fork{\texttt{maxval}}{if \(\texttt{src}(x,y) > \texttt{thresh}\)}{0}{otherwise}\f]
	THRESH_BINARY_INV = 1, //!< \f[\texttt{dst} (x,y) =  \fork{0}{if \(\texttt{src}(x,y) > \texttt{thresh}\)}{\texttt{maxval}}{otherwise}\f]
	THRESH_TRUNC      = 2, //!< \f[\texttt{dst} (x,y) =  \fork{\texttt{threshold}}{if \(\texttt{src}(x,y) > \texttt{thresh}\)}{\texttt{src}(x,y)}{otherwise}\f]
	THRESH_TOZERO     = 3, //!< \f[\texttt{dst} (x,y) =  \fork{\texttt{src}(x,y)}{if \(\texttt{src}(x,y) > \texttt{thresh}\)}{0}{otherwise}\f]
	THRESH_TOZERO_INV = 4, //!< \f[\texttt{dst} (x,y) =  \fork{0}{if \(\texttt{src}(x,y) > \texttt{thresh}\)}{\texttt{src}(x,y)}{otherwise}\f]
	THRESH_MASK       = 7,
	THRESH_OTSU       = 8, //!< flag, use Otsu algorithm to choose the optimal threshold value
	THRESH_TRIANGLE   = 16 //!< flag, use Triangle algorithm to choose the optimal threshold value
};
	*/

	if (cvbag::isImageEmpty(image, "adaptiveThreshold")) return -1;
	if (image.channels() == 3) cv::cvtColor(image, dst, cv::COLOR_BGR2GRAY);
	cv::threshold(dst, dst, th, maxval, mode);

	return 0;
}

int cvbag::adaptiveThreshold(const cv::Mat &image, cv::Mat &dst, int blockSize, double C, double maxval,
	int adaptiveMethod, int thresholdType)
{
	if (cvbag::isImageEmpty(image, "adaptiveThreshold")) return -1;
	//blockSize must be an odd number,like 3,5,7...
	if (blockSize % 2 == 0) blockSize += 1;
	if (image.channels() == 3) {
		cv::cvtColor(image, dst, cv::COLOR_BGR2GRAY);
		cv::adaptiveThreshold(dst, dst, maxval, adaptiveMethod, thresholdType, blockSize, C);
	} 
	else {
		cv::adaptiveThreshold(image, dst, maxval, adaptiveMethod, thresholdType, blockSize, C);
	}

	
	return 0;
}

int  cvbag::findContours(const cv::Mat &binaryImage, std::vector<std::vector<cv::Point>> &contours, 	int topologyMode , int contoursType )
{
	/** Contour retrieval modes */
	/*enum
	{
		CV_RETR_EXTERNAL = 0,
		CV_RETR_LIST = 1,
		CV_RETR_CCOMP = 2,
		CV_RETR_TREE = 3,
		CV_RETR_FLOODFILL = 4
	};*/

	/** Contour approximation methods */
	/*enum
	{
		CV_CHAIN_CODE = 0,
		CV_CHAIN_APPROX_NONE = 1,
		CV_CHAIN_APPROX_SIMPLE = 2,
		CV_CHAIN_APPROX_TC89_L1 = 3,
		CV_CHAIN_APPROX_TC89_KCOS = 4,
		CV_LINK_RUNS = 5
	};*/

	if (cvbag::isImageEmpty(binaryImage, "findContours")) return -1;

	std::vector<cv::Vec4i> hierarchy;
	if (binaryImage.channels() == 3) return -1;
	cv::findContours(binaryImage, contours, topologyMode, contoursType);

	return 0;
}

int cvbag::drawContours(cv::Mat &image, const std::vector<std::vector<cv::Point>> &contours,	int contoursIdx , int b , int g , int r )
{
	if (cvbag::isImageEmpty(image, "drawContours")) return -1;
	cv::drawContours(image, contours, contoursIdx, cv::Scalar(b, g, r));
	return 0;
}

int cvbag::dilate(const cv::Mat &binaryImage, cv::Mat &dst, const  int ksize , const int kernelMode )
{
	/*	MORPH_ERODE
		MORPH_DILATE
		MORPH_OPEN		dst = open(src, element) = dilate(erode(src, element))
		MORPH_CLOSE		dst = close(src, element) = erode(dilate(src, element))
		MORPH_GRADIENT		dst = morph_grad(src, element) = dilate(src, element)−erode(src, element)
		MORPH_TOPHAT		dst = tophat(src, element) = src−open(src, element)
		MORPH_BLACKHAT		dst = blackhat(src, element) = close(src, element)−src
		MORPH_HITMISS
		"hit or miss" . - Only supported for CV_8UC1 binary images.
		A tutorial canbe found in the documentation
	*/

	/*
	enum MorphTypes{
	MORPH_ERODE    = 0,
	MORPH_DILATE   = 1,
	MORPH_OPEN     = 2,
	MORPH_CLOSE    = 3,
	MORPH_GRADIENT = 4,
	MORPH_TOPHAT   = 5,
	MORPH_BLACKHAT = 6,
	MORPH_HITMISS  = 7
	 };
	*/
	/*
	enum MorphShapes {
	MORPH_RECT    = 0, //!< a rectangular structuring element:  \f[E_{ij}=1\f]
	MORPH_CROSS   = 1, //!< a cross-shaped structuring element:
					   //!< \f[E_{ij} =  \fork{1}{if i=\texttt{anchor.y} or j=\texttt{anchor.x}}{0}{otherwise}\f]
	MORPH_ELLIPSE = 2 //!< an elliptic structuring element, that is, a filled ellipse inscribed
					  //!< into the rectangle Rect(0, 0, esize.width, 0.esize.height)
	};
	*/
	if (cvbag::isImageEmpty(binaryImage, "dilate")) return -1;
	if (binaryImage.channels() == 3) return -1;
	cv::Mat element = cv::getStructuringElement(kernelMode, cv::Size(ksize, ksize));
	cv::morphologyEx(binaryImage, dst, 1, element);
	return 0;
}

int cvbag::erode(const cv::Mat &binaryImage, cv::Mat &dst, const int ksize , const int kernelMode )
{
	/*	MORPH_ERODE
		MORPH_DILATE
		MORPH_OPEN		dst = open(src, element) = dilate(erode(src, element))
		MORPH_CLOSE		dst = close(src, element) = erode(dilate(src, element))
		MORPH_GRADIENT		dst = morph_grad(src, element) = dilate(src, element)−erode(src, element)
		MORPH_TOPHAT		dst = tophat(src, element) = src−open(src, element)
		MORPH_BLACKHAT		dst = blackhat(src, element) = close(src, element)−src
		MORPH_HITMISS
		"hit or miss" . - Only supported for CV_8UC1 binary images.
		A tutorial canbe found in the documentation
	*/

	/*
	enum MorphTypes{
	MORPH_ERODE    = 0,
	MORPH_DILATE   = 1,
	MORPH_OPEN     = 2,
	MORPH_CLOSE    = 3,
	MORPH_GRADIENT = 4,
	MORPH_TOPHAT   = 5,
	MORPH_BLACKHAT = 6,
	MORPH_HITMISS  = 7
	 };
	*/
	/*
	enum MorphShapes {
	MORPH_RECT    = 0, //!< a rectangular structuring element:  \f[E_{ij}=1\f]
	MORPH_CROSS   = 1, //!< a cross-shaped structuring element:
					   //!< \f[E_{ij} =  \fork{1}{if i=\texttt{anchor.y} or j=\texttt{anchor.x}}{0}{otherwise}\f]
	MORPH_ELLIPSE = 2 //!< an elliptic structuring element, that is, a filled ellipse inscribed
					  //!< into the rectangle Rect(0, 0, esize.width, 0.esize.height)
	};
	*/
	if (cvbag::isImageEmpty(binaryImage, "erode")) return -1;
	if ( binaryImage.channels() == 3) return -1;
	cv::Mat element = cv::getStructuringElement(kernelMode, cv::Size(ksize, ksize));
	cv::morphologyEx(binaryImage, dst, 0, element);
	return 0;
}

int cvbag::open(const cv::Mat &binaryImage, cv::Mat &dst, const int ksize, const int kernelMode)
{
	
	if (cvbag::isImageEmpty(binaryImage, "erode")) return -1;
	if (binaryImage.channels() == 3) return -1;
	cv::Mat element = cv::getStructuringElement(kernelMode, cv::Size(ksize, ksize));
	cv::morphologyEx(binaryImage, dst, 2, element);
	return 0;
}

int cvbag::close(const cv::Mat &binaryImage, cv::Mat &dst, const int ksize, const int kernelMode)
{

	if (cvbag::isImageEmpty(binaryImage, "erode")) return -1;
	if (binaryImage.channels() == 3) return -1;
	cv::Mat element = cv::getStructuringElement(kernelMode, cv::Size(ksize, ksize));
	cv::morphologyEx(binaryImage, dst, 3, element);
	return 0;
}

int cvbag::gammaTransform_threeChannels(const cv::Mat &image, cv::Mat &dst, const int table[])
{
	std::vector<cv::Mat> channelsImage;
	std::vector<cv::Mat> channelsImage_dst;
	cv::split(image, channelsImage);
	for (int i = 0; i < channelsImage.size(); i++)
	{
		channelsImage_dst.push_back(cv::Mat::zeros(cv::Size(image.cols, image.rows), CV_8UC1));

	}

	for (int i = 0; i < channelsImage.size(); i++)
	{
		gammaTransform(channelsImage[i], channelsImage_dst[i], table);
	}
	cv::merge(channelsImage_dst, dst);

	return 0;
}

int cvbag::getGammaTable(const double gamma, int *a, const int num )
{
	for (int i = 0; i < num; i++)
	{
		a[i] = int(pow(i / 255.0, gamma) *255.0);
	}

	return 0;
}

int cvbag::gamma(const cv::Mat &image, cv::Mat &dst, const double gamma )
{
	if (image.empty()) return -1;

	int table[256] = { 0 };
	getGammaTable(gamma, table);

	gammaTransform(image, dst, table);


	return 0;
}

int cvbag::gammaTransform(const cv::Mat &image, cv::Mat &dst, const int  table[])
{
	if (image.empty()) return -1;

	if (image.channels() == 3)
	{
		gammaTransform_threeChannels(image, dst, table);
	}

	if (dst.empty()) dst = cv::Mat::zeros(cv::Size(image.cols, image.rows), CV_8UC1);

	const uchar * ps = NULL;
	uchar * pd = NULL;

	for (int i = 0; i < image.rows; i++)
	{
		ps = image.ptr<uchar>(i);
		pd = dst.ptr<uchar>(i);
		for (int j = 0; j < image.cols; j++)
		{
			*(pd + j) = table[int(*(ps + j))];
		}
	}
	return 0;
}

int cvbag::gamma_picewiseLinear(const cv::Mat &image, cv::Mat &dst, const int src1, const int dst1, const int src2, const int dst2)
{
	if (image.empty()) return -1;

	int table[256] = { 0 };
	if (src1<=0 | src1 > 255 | src1>=src2 | src2 > 255 | dst1<0 | dst1 > 255 | dst2<0 | dst2 > 255) return -1;

	getGammaTable_piecewiseLinear(table,src1,dst1,src2,dst2);

	gammaTransform(image, dst, table);

	return 0;
}

int cvbag::getGammaTable_piecewiseLinear(int *a, const int src1 , const int dst1 , const int src2 , const int dst2 )
{
	for (int i = 0; i < src1; i++)
	{
		a[i] = int(float(dst1) / float(src1)*i);
	}

	for (int i = src1; i < src2; i++)
	{
		a[i] = int(float(dst2 - dst1) / float(src2 - src1) * (i - src1) + dst1);
	}

	for (int i = src2; i < 256; i++)
	{
		a[i] = int(float(255 - dst2) / float(255 - src2) * (i - src2) + dst2);
	}

	return 0;
}


int demo()
{
	//const std::string fileName = "K:\\imageData\\golden_pad\\204.bmp";
	const std::string fileName = "K:\\imageData\\lena\\Lena.png";

	//cvbag tool;

	//showImage
	cv::Mat image = cv::imread(fileName);
	cvbag::showImage(image, "image",0,0);

	//gauss smooth
	cv::Mat gauss;
	cvbag::gaussBlur(image, gauss);
	cvbag::showImage(gauss, "gauss");

	//sobel edge detect
	cv::Mat sobel_xy;
	cvbag::sobel_x(gauss, sobel_xy);
	convert format CV_64F to CV_8U ,so that the image can use cv::imshow to show image.
	cv::convertScaleAbs(sobel_xy, sobel_xy);
	cvbag::showImage(sobel_xy, "sobel_xy");

	//otsu
	cv::Mat otsu;
	cvbag::otsu(gauss, otsu);
	cvbag::showImage(otsu, "otsu");

	//threshold
	cv::Mat threshold;
	cvbag::threshold(gauss, threshold, 120,8+1);
	cvbag::showImage(threshold, "threshold");

	//adaptiveThreshold
	cv::Mat adaptiveThreshold;
	cvbag::adaptiveThreshold(gauss, adaptiveThreshold,11,8 );
	cvbag::showImage(adaptiveThreshold, "adaptiveThreshold");

	//canny
	cv::Mat canny;
	cvbag::canny(image, canny, 120, 180);
	cvbag::showImage(canny, "canny");

	//contours
	std::vector<std::vector<cv::Point>> contours;
	cvbag::findContours(adaptiveThreshold, contours);
	cv::Mat conImage = gauss.clone();
	cvbag::drawContours(conImage, contours, -1, 0, 255, 0);
	cvbag::showImage(conImage, "contours");

	//dilate
	cv::Mat dilate;
	cvbag::dilate(otsu, dilate, 3, 0);
	cvbag::showImage(dilate, "dilate");

	//erode
	cv::Mat erode;
	cvbag::erode(otsu, erode, 3, 0);
	cvbag::showImage(erode, "erode");

	//open
	cv::Mat open;
	cvbag::open(otsu, open);
	cvbag::showImage(open, "open");

	//close
	cv::Mat close;
	cvbag::close(otsu, close);
	cvbag::showImage(close, "close");

	//gamma
	cv::Mat gamma;
	cvbag::gamma(image, gamma, 2);
	cvbag::showImage(gamma, "gamma");

	//gamma_piecewiseLinaer
	cv::Mat gamma_piece;
	cvbag::gamma_picewiseLinear(image, gamma_piece, 120, 60, 160, 200);
	cvbag::showImage(gamma_piece, "gamma_piece");

	return 0;
}



int main()
{
	demo();
	return 0;
}
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值