新生研讨课

基于OpenCV的马赛克实现方案

 

我是来自格院电工2017200501032的任欣宇

在新生研讨会上,曾院长生动地向我们介绍了图像处理的相关技术,包括视频防抖技术,基于图像识别技术的照片处理等,其中给我留下最深印象的便是曾院长讲述的马赛克处理方案。课后我查询了各类学习资料,进行了相关内容的学习,并进行了相关实验。

技术背景

马赛克指现行广为使用的一种图像(视频)处理手段,此手段将影像特定区域的色阶细节劣化并造成色块打乱的效果,因为这种模糊看上去有一个个的小格子组成,便形象的称这种画面为马赛克。其目的通常是使之无法辨认。 

就用RGB来举例子,R(red红色),G(green绿色),B(blue蓝色)。这三种颜色每种都有0~255范围内的强度值,数字越高越亮,例如,亮红色使用 R 值 255、G 值 0 和 B 值 0,有色光可被无色光冲淡并变亮。如蓝色光与白光相遇,结果是产生更加明亮的浅蓝色光。所以R、G、B的值的不同来混合颜色

实践操作

在实际应用中,我们利用矩阵,使图片中的RGB参数向量化,再利用OpenCV对图像矩阵进行变换,此实验中,我们使用图像的周围颜色填充马赛克颜色,再规定每个马赛克大小,对于鼠标点过的区域进行设计的马赛克覆盖,实现图片的加码。

OpenCV实现为图片添加马赛克功能:

#include <opencv2\core\core.hpp>
#include <opencv2\highgui\highgui.hpp>
#include <opencv2\imgproc\imgproc.hpp>
#include <iostream>
 
using namespace cv;
using namespace std;
 
Mat inputImage;
Mat inputImage_mosaic;
Mat inputImage_clone;
 
//马赛克的范围
int neightbourhood = 20;
 
//记录鼠标的状态,1为鼠标左键按下,0位松开状态
int mouseStatus = 0;
 
void onMouse(int events, int x, int y, int flag, void* ustg);
 
//创建马赛克
void createMosaicImage(Mat inputMat, Mat& outputMat, int size);
 
//设置马赛克区域
void setMosaic(Mat& inputMat, Rect rect);
 
int main(void){
	inputImage = imread("test2.jpg");
	inputImage_clone = inputImage.clone();
	createMosaicImage(inputImage, inputImage_mosaic, neightbourhood);
 
	namedWindow("showImage", 0);
	setMouseCallback("showImage", onMouse);
 
	waitKey();
	return 0;
}
 
void createMosaicImage(Mat inputMat, Mat& outputMat, int size){
	RNG rng;
	int height = inputMat.rows;
	int width = inputMat.cols;
	Mat padding;
	Mat tempMat;
 
	//为了方便后面的计算,将输入的图像大小扩充到宽高都是size的倍数
	copyMakeBorder(inputMat, padding, 0, size - inputMat.rows % size, 0, size - inputMat.cols % size, BORDER_REPLICATE);
	tempMat = padding.clone();
	
	for (int row = 0; row < padding.rows; row += size){
		for (int col = 0; col < padding.cols; col += size){
			int rand_x = rng.uniform(0, size);
			int rand_y = rng.uniform(0, size);
			Rect rect = Rect(col, row, size, size);
			Mat roi = tempMat(rect);
			Scalar color = Scalar(padding.at<Vec3b>(row + rand_y, col + rand_x)[0], \
				padding.at<Vec3b>(row + rand_y, col + rand_x)[1], \
				padding.at<Vec3b>(row + rand_y, col + rand_x)[2]);
			roi.setTo(color);
		}
	}
	outputMat = tempMat(Rect(0, 0, width, height)).clone();
}
 
void setMosaic(Mat& inputMat, Rect rect){
	Mat roi = inputMat(rect);
	Mat tempRoi = inputImage_mosaic(rect);
	tempRoi.copyTo(roi);
}
 
void onMouse(int events, int x, int y, int flag, void* ustg){
 
	//当鼠标移除图片区域的时候,不做操作
	if (x < 0 || x > inputImage.cols || y < 0 || y > inputImage.rows){
		return;
	}
 
	//马赛克块的位置信息
	int x_left, x_right, y_top, y_bottom;
	x - neightbourhood <= 0 ? x_left = 0 : x_left = x - neightbourhood;
	x + neightbourhood > inputImage.cols ? x_right = inputImage.cols: x_right = x + neightbourhood;
	y - neightbourhood <= 0 ? y_top = 0 : y_top = y - neightbourhood;
	y + neightbourhood > inputImage.rows ? y_bottom = inputImage.rows: y_bottom = y + neightbourhood;
 
	if (events == CV_EVENT_LBUTTONDOWN){
		mouseStatus = 1;
		setMosaic(inputImage_clone, Rect(x_left, y_top, x_right - x_left, y_bottom - y_top));
	}
	else if (events == CV_EVENT_MOUSEMOVE){
		if (mouseStatus == 1){
			setMosaic(inputImage_clone, Rect(x_left, y_top, x_right - x_left, y_bottom - y_top));
		}
		else{
			//nothing
		}
	}
	else if (events == CV_EVENT_LBUTTONUP){
		mouseStatus = 0;
	}
	else {
		//cout << "nothing" << endl;
	}
	imshow("showImage", inputImage_clone);
}

这种马赛克的图层是最简单的用周围颜色覆盖原图的RGB值,也利于逆马赛克,例如微信的打码。

不过遗憾的是,去除马赛克时,需要用大量图片,用神经网络一层一层的提取特征并压缩,找出解决方案,其中涉及的概率论知识有些复杂,对于现在的我有些难以代码实现,希望不久的将来我能针对这种马赛克写出解码方案。

此次参加新生研讨课,让我对于线性代数与概率论的应用有了更深的认识,并产生了对于用深度学习解决图像问题的兴趣,使我受益匪浅。在此希望将来的新生研讨课能够办的更好,使更多同学产生学习电子类的兴趣。

猜你喜欢

转载自blog.csdn.net/richie_ren/article/details/84490872