新生研討課
阿新 • • 發佈:2018-11-25
基於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值,也利於逆馬賽克,例如微信的打碼。
不過遺憾的是,去除馬賽克時,需要用大量圖片,用神經網路一層一層的提取特徵並壓縮,找出解決方案,其中涉及的概率論知識有些複雜,對於現在的我有些難以程式碼實現,希望不久的將來我能針對這種馬賽克寫出解碼方案。
此次參加新生研討課,讓我對於線性代數與概率論的應用有了更深的認識,併產生了對於用深度學習解決影象問題的興趣,使我受益匪淺。在此希望將來的新生研討課能夠辦的更好,使更多同學產生學習電子類的興趣。