1. 程式人生 > >新生研討課

新生研討課

基於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值,也利於逆馬賽克,例如微信的打碼。

不過遺憾的是,去除馬賽克時,需要用大量圖片,用神經網路一層一層的提取特徵並壓縮,找出解決方案,其中涉及的概率論知識有些複雜,對於現在的我有些難以程式碼實現,希望不久的將來我能針對這種馬賽克寫出解碼方案。

此次參加新生研討課,讓我對於線性代數與概率論的應用有了更深的認識,併產生了對於用深度學習解決影象問題的興趣,使我受益匪淺。在此希望將來的新生研討課能夠辦的更好,使更多同學產生學習電子類的興趣。