OpenCV入门例程:裁剪图片、模糊检测、黑屏检测

初级代码游戏的专栏介绍与文章目录-CSDN博客

我的github:codetoys,所有代码都将会位于ctfc库中。已经放入库中我会指出在库中的位置。

这些代码大部分以Linux为目标但部分代码是纯C++的,可以在任何平台上使用。


        本例程运行环境为CentOS7,64位。代码很简单,三个函数分别裁剪图片、模糊检测、黑屏检测,最后是测试代码。(这个代码应该也是可以在windows上运行的,不确定是不是要经过修改)

        需要预先安装OpenCV4。

目录

一、编译参数

二、代码结构(省略的部分在后面)

三、裁剪图片

四、模糊检测

五、黑屏检测

六、测试代码

七、附加说明


一、编译参数

         在OpenCV官网下载安装:

        注意,本人所用版本没有这么新,不过应该不影响。 

        程序使用OpenCV需要头文件和库:

头文件包含目录,按照你的安装位置
-I /usr/local/include/opencv4/
链接库,这是全部,程序本身应该不需要链接这么多
 -lopencv_core -lopencv_imgcodecs -lopencv_highgui -lopencv_calib3d -lopencv_dnn -lopencv_features2d \
 -lopencv_flann -lopencv_imgproc -lopencv_ml -lopencv_objdetect -lopencv_photo -lopencv_stitching 

        如果不知道安装到哪里了,用find搜索一下就可以了。 

二、代码结构(省略的部分在后面)

#include "opencv2/opencv.hpp"
#include <opencv2/imgproc/types_c.h>
using namespace cv;

//图像处理类
class CMyPic
{
private:
public:
	//裁剪图片
	static bool ClipPic(char const* infile, int x, int y, int width, int heigh, char const* outfile)
	{
		。。。。。。
	}
	//模糊检测
	static double isImageBlurry(cv::Mat& img)
	{
		。。。。。
	}
	// cast 占比值,阈值为0.85,占比大于阈值认为黑屏
	static double detect_blackscreen(cv::Mat input_img)
	{
		。。。。。。
	}
	static bool CMyPic_test()
	{
		。。。。。。
	}
};

        三个功能三个函数,还有一个是测试。其实四个函数都是独立的,并不需要包装起来。

三、裁剪图片

	//裁剪图片
	static bool ClipPic(char const* infile, int x, int y, int width, int heigh, char const* outfile)
	{
		Mat pic = imread(infile);
		if (NULL == pic.data)
		{
			thelog << "imread失败" << ende;
			return false;
		}
		Rect rect(x, y, width, heigh);
		Mat newpic = pic(rect);
		if (NULL == newpic.data)
		{
			thelog << "剪切失败" << ende;
			return false;
		}
		if (!imwrite(outfile, newpic))
		{
			thelog << "imwrite失败" << ende;
			return false;
		}
		return true;
	}

        裁剪图片不在后面的测试代码中,因为这个代码一直在使用,所以也不用测试。

        功能很简单,打开输入文件,读取RECT范围到新图片,输出到outfile,文件格式OpenCV会根据文件后缀名自动处理。

        用到的几个OpenCV功能:

  • imread(文件名) 读取图片文件到Mat结构,根据文件扩展名自动识别格式
  • Mat::Mat(RECT) 剪切图片……这也太简单了
  • imwrite(文件名,Mat对象) 写文件,根据文件扩展名自动选择输出格式

四、模糊检测

	//模糊检测
	static double isImageBlurry(cv::Mat& img)
	{
		cv::Mat matImageGray;
		// converting image's color space (RGB) to grayscale
		cv::cvtColor(img, matImageGray, CV_BGR2GRAY);
		cv::Mat dst, abs_dst;
		cv::Laplacian(matImageGray, dst, CV_16S, 3);
		cv::convertScaleAbs(dst, abs_dst);
		cv::Mat tmp_m, tmp_sd;
		double m = 0, sd = 0;
		//int threshold = 1000;
		cv::meanStdDev(dst, tmp_m, tmp_sd);
		m = tmp_m.at<double>(0, 0);
		sd = tmp_sd.at<double>(0, 0);
		return (sd * sd);
	}

        这个就有点复杂了,先转换成灰度,再执行拉普拉斯算子,然后……好吧,其实我也不懂。

        用到的几个OpenCV功能:

  • cvtColor 转换颜色
  • Laplacian 拉普拉斯算子
  • convertScaleAbs 取绝对值
  • meanStdDev 计算平均值和标准差

五、黑屏检测

	// cast 占比值,阈值为0.85,占比大于阈值认为黑屏
	static double detect_blackscreen(cv::Mat input_img)
	{
		cv::Mat gray_img;
		cv::cvtColor(input_img, gray_img, CV_BGR2GRAY);

		long dark_sum = 0;
		for (long i = 0; i < gray_img.rows; ++i)
		{
			for (long j = 0; j < gray_img.cols; ++j)
			{
				if (gray_img.at<uchar>(i, j) < 20)
				{
					++dark_sum;
				}
			}
		}

		return dark_sum / double(gray_img.total());
	}

        先转换成灰度,再计算灰度小于20的点的占比。 返回的是占比,跟阈值比较即可。

        这个算法只用到了转换颜色cvtColor。

六、测试代码

	static bool CMyPic_test()
	{
		struct dirent* drip;
		DIR* dp;
		string dirname="目录";

		if ((dp = opendir(dirname.c_str())) == NULL)
		{
			thelog << "Error open dir " << dirname << " : " << strerror(errno) << ende;
			return false;
		}
		int ret = 0;
		while ((drip = readdir(dp)) != NULL)
		{
			if (strcmp(drip->d_name, ".") == 0 || strcmp(drip->d_name, "..") == 0)
			{
				continue;
			}

			string fullname;
			fullname = dirname + "/" + drip->d_name;
			//thelog<<fullname<<endi;
			bool isdir = IsDir(fullname.c_str());
			if (isdir)
			{
				thelog << fullname << "是个目录" << endi;
				continue;
			}

			string ext = ".jpg";//任务文件扩展名
			int d_name_len = strlen(drip->d_name);
			if (0 != strcmp(ext.c_str(), drip->d_name + d_name_len - ext.size()))
			{
				continue;
			}

			Mat pic = imread(fullname.c_str());
			if (NULL == pic.data)
			{
				thelog << "imread失败" << ende;
				return false;
			}
			
			//检测模糊
			double Blurry = isImageBlurry(pic);
			if (Blurry < 1000)
			{
				thelog << fullname << "模糊 " << Blurry << endi;
			}
			else
			{
				//thelog << fullname<< "不模糊" << endi;
			}
			//检测黑屏
			double Black = detect_blackscreen(pic);
			if (Black > 0.85)
			{
				thelog << fullname << "黑屏 " << Black << endi;
			}
			else
			{
				//thelog << fullname << "不黑屏" << endi;
			}

			char buf[128];
			sprintf(buf, ".%ld.%ld.jpg", (long)Blurry, (long)(Black*100));
			if (!imwrite(((string)drip->d_name + buf).c_str(), pic))
			{
				thelog << "imwrite失败" << ende;
				return false;
			}
		}
		closedir(dp);

		thelog << dirname << " 处理完毕" << endi;
		return true;
	}

        这个测试代码读取目录下的所有文件输出判断结果。 

七、附加说明

        测试代码用到了thelog,功能就是日志输出,替换为cout,ende和endi替换为endl即可。

        操作目录的部分需要包含头文件dirent.h。IsDir的实现是这样的:

		bool IsDir(char const * strPathName)
		{
			struct stat statBuf;

			if (stat(strPathName, &statBuf) == -1)
			{//这里总是返回-1,不知道是什么原因
				cout << "stat error : " << strPathName << " " << strerror(errno) << endl;
				return false;
			}

			return(statBuf.st_mode & S_IFDIR);
		}

        这个函数似乎有BUG,没搞清怎么回事,这个代码以前是可以用的,也不知道怎么回事,不过不影响测试代码的主要目的。


(这里是文档结束)

  • 14
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值