《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);
}
嗯,以上是代码加效果部分!