《mastering opencv》第一章学习
学习的资料,《mastering opencv》,这本教程非常金典,编写者之一是opencv源码的重要贡献者。里面的例子都是非常经典,有趣,并且涉及的算法都是应用最广的。我建议阅读英文原著版。我英语只有4级,刚开始读是蛮吃力的,越到后面就越有意思。网上有很多的资源下载,并且有每章的源码。非常好用,下面是我的学习总结:
第一章的名字叫 Cartoonifier and Skin Changer for Android,讲的内容差不多是这样的:如何将一张图片(最好是人脸图片)如何变成漂亮的素描图片。如何变成萌萌的卡通图片,更恐怖的是如何将一个看上去人畜无害的图片变成一个恐怖的图片,最后将一张图片变成外星人的图片。非常有意思,对,先啥也不说,看看效果:
界面:
素描处理:
卡通处理:
恐怖处理:
sobel滤波处理
结束界面:
下面是代码部分:
主函数:Cartoonnifier.cpp
/***************************************************************************** * Cartoonifier.cpp, for Desktop. * Converts a real-life camera stream to look like a cartoon. * This file is for a desktop executable, but the cartoonifier can also be used in an Android / iOS project. ****************************************************************************** * by Li jie, 2017.8.17 ****************************************************************************** * Ch1 of the book "Mastering OpenCV with Practical Computer Vision Projects" * Copyright Packt Publishing 2012. *****************************************************************************/ #include "stdafx.h" #include <stdlib.h> #include <stdio.h> #include <highgui.h> #include <cv.h> #include <iostream> #include "opencv2/opencv.hpp" #include "cartoon.h" // Cartoonify a photo. #include "highgui.h" using namespace std; using namespace cv; const int DESIRED_CAMERA_WIDTH = 640; const int DESIRED_CAMERA_HEIGHT = 480; const char *windowName = "Cartoonifier"; #if !defined DEBUG #define DEBUG 0 #endif int _tmain(int argc, _TCHAR* argv[]) { cout << "Cartoonifier, by Li Jie 2017.8.12" << endl; cout << "Converts real-life images to cartoon-like images." << endl; cout << "Compiled with OpenCV version " << CV_VERSION << endl; cout << endl; cout << "Keyboard commands (press in the GUI window):" << endl; cout << " q: Quit the program." << endl; cout << " s: change to sketch_img " << endl; cout << " c: change to cartoonifier_img." << endl; cout << " e: change to Evil /scary_img." << endl; cout << " d: change to Sobel_img." << endl; cout << endl; //namedWindow(windowName); // Resizable window, might not work on Windows. Mat src = imread("C:\\Users\\Administrator\\Desktop\\lenna.bmp",-1 ); Mat dest; if (src.empty()) { cout << "fial!"<<endl; return -1; } char Keyboard_commands[10]; cin.getline(Keyboard_commands, 10); namedWindow("Src_img", WINDOW_AUTOSIZE); imshow("Src_img", src); //waitKey(20); switch (*Keyboard_commands) { case 'q': return -1; case 's': { sketch_img(src, dest); cin.getline(Keyboard_commands, 10); } case 'c':{ cartoonifier_img(src, dest); cin.getline(Keyboard_commands, 10); } case 'e':{ scary_img(src, dest); cin.getline(Keyboard_commands, 10); } case 'd':{ Sobel_img(src, dest); cin.getline(Keyboard_commands, 10); } default: { cout << "You have entered a wrong order!Please re-enter!" << endl; } } destroyWindow("Src_img"); return 0; }
接下来是函数实现部分:cartoon.cpp#include "cartoon.h" //图片素描化处理 void sketch_img(Mat src_img, Mat disposed_img) { Mat gray,edges; cvtColor(src_img, gray, CV_BGR2GRAY);//灰度 medianBlur(gray, gray, MEDIAN_BLUR_FILTER_SIZE);//中值滤波,做平滑处理,即降噪 Laplacian(gray, edges, CV_8U, LAPLACIAN_FILTER_SIZE);//Laplacian锐化 threshold(edges, disposed_img, EDGES_THRESHOLD, 255, THRESH_BINARY_INV);//灰度图像进行阈值操作得到二值图像 namedWindow("sketch_img", WINDOW_AUTOSIZE); imshow("sketch_img", disposed_img); waitKey(0); destroyWindow("sketch_img"); } //图片卡通化处理 void cartoonifier_img(Mat src_img, Mat disposed_img) { Mat gray, edges; cvtColor(src_img, gray, CV_BGR2GRAY);//灰度 medianBlur(gray, gray, MEDIAN_BLUR_FILTER_SIZE);//中值滤波,做平滑处理,即降噪 Laplacian(gray, edges, CV_8U, LAPLACIAN_FILTER_SIZE);//Laplacian锐化 threshold(edges, disposed_img, EDGES_THRESHOLD, 255, THRESH_BINARY_INV);//灰度图像进行阈值操作得到二值图像 //上面的步骤与sketch_img()函数中一模一样 //进行卡通化处理 Mat smallImg; Size smallSize; Size size; size = src_img.size(); smallSize.width = size.width / 2; smallSize.height = size.height / 2; smallImg = Mat(smallSize, CV_8UC3); resize(src_img, smallImg, smallSize, 0, 0, INTER_LINEAR);//图片的大小调整,即图像的缩放 // Perform many iterations of weak bilateral filtering, to enhance the edges // while blurring the flat regions, like a cartoon. Mat tmp = Mat(smallSize, CV_8UC3); int repetitions = 7; for (int i = 0; i < repetitions; i++) { int size = 9; double sigmaColor = 9; double sigmaSpace = 7; //Bilateral方法(双边滤波)ilateral blur相对于传统的高斯blur来说很重要的一个特性即可可以保持边缘(Edge Perseving), //这个特点对于一些图像模糊来说很有用,ps美女图像上的效果very good! bilateralFilter(smallImg, tmp, size, sigmaColor, sigmaSpace); bilateralFilter(tmp, smallImg, size, sigmaColor, sigmaSpace); } // Go back to the original scale. resize(smallImg, src_img, size, 0, 0, INTER_LINEAR); Mat dst; dst.setTo(0); //disposed_img就是每个字节上的一个标志,标志位=0,不copy;标志位!=0,则copy(按字节) src_img.copyTo(dst, disposed_img); namedWindow("cartoonifier_img", WINDOW_AUTOSIZE); imshow("cartoonifier_img", dst); waitKey(0); destroyWindow("cartoonifier_img"); } //图片恐怖化处理 void scary_img(Mat src_img, Mat disposed_img) { Mat gray; cvtColor(src_img, gray, CV_BGR2GRAY);//灰度 medianBlur(gray, gray, MEDIAN_BLUR_FILTER_SIZE);//中值滤波,做平滑处理,即降噪 Size size = src_img.size(); Mat mask = Mat(size, CV_8U); Mat edges = Mat(size, CV_8U); Mat edges2; Scharr(gray, edges, CV_8U, 1, 0); Scharr(gray, edges2, CV_8U, 1, 0, -1); edges += edges2; threshold(edges, mask, 12, 255, THRESH_BINARY_INV); medianBlur(mask, mask, 3); namedWindow("scary_img", WINDOW_AUTOSIZE); imshow("scary_img", mask); waitKey(0); destroyWindow("scary_img"); } static void on_Sobel(int, void*);//Sobel边缘检测窗口滚动条的回调函数 //原图,原图的灰度版,目标图 Mat g_srcImage, g_srcGrayImage, g_dstImage; //Sobel边缘检测相关变量 Mat g_sobelGradient_X, g_sobelGradient_Y; Mat g_sobelAbsGradient_X, g_sobelAbsGradient_Y; int g_sobelKernelSize = 1;//TrackBar位置参数 //图片Sobel 算子化处理 void Sobel_img(Mat src_img, Mat disposed_img) { g_srcImage = src_img; g_dstImage = disposed_img; Mat gray; Mat g_sobelGradient_X, g_sobelGradient_Y; Mat g_sobelAbsGradient_X, g_sobelAbsGradient_Y; int g_sobelKernelSize = 1;//TrackBar位置参数 cvtColor(src_img, gray, CV_BGR2GRAY);//灰度 namedWindow("【效果图】Sobel边缘检测", CV_WINDOW_AUTOSIZE); createTrackbar("参数值:", "【效果图】Sobel边缘检测", &g_sobelKernelSize, 3, on_Sobel); on_Sobel(0, 0); } void on_Sobel(int, void*) { // 求 X方向梯度 Sobel(g_srcImage, g_sobelGradient_X, CV_16S, 1, 0, (2 * g_sobelKernelSize + 1), 1, 1, BORDER_DEFAULT); convertScaleAbs(g_sobelGradient_X, g_sobelAbsGradient_X);//计算绝对值,并将结果转换成8位 // 求Y方向梯度 Sobel(g_srcImage, g_sobelGradient_Y, CV_16S, 0, 1, (2 * g_sobelKernelSize + 1), 1, 1, BORDER_DEFAULT); convertScaleAbs(g_sobelGradient_Y, g_sobelAbsGradient_Y);//计算绝对值,并将结果转换成8位 // 合并梯度 addWeighted(g_sobelAbsGradient_X, 0.5, g_sobelAbsGradient_Y, 0.5, 0, g_dstImage); //显示效果图 imshow("【效果图】Sobel边缘检测", g_dstImage); waitKey(0); }
嗯,以上是代码加效果部分!