OpenCV学习笔记_实现马赛克功能

实现用按下鼠标左键拖动时,在鼠标经过的路径上打上马赛克。

马赛克的原理是将图像中选中区域的像素用这个选中区域中的某一像素覆盖。

为了不让鼠标重复经过图像中同一个的时候,选取不一样的像素,该程序将在输入图片的时候,就实现了全图的马赛克效果。而当鼠标划过的时候,程序只是将实现马赛克的图片的指定位置复制到显示的图像中。效果类似于QQ截图中的马赛克。

#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;

//记录鼠标的状态,0为鼠标左键未按下或弹起,1为鼠标左键按下
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);
}
效果图

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值