Android系统上生成卡通画
不知道为什么外星人那块的函数运行到floodfill的时候一直不出结果……其他部分都很正常orz
/* main.cpp */
#include <opencv2/opencv.hpp>
#include <iostream>
#include <math.h>
#include "cartoon.h"
using namespace std;
using namespace cv;
int main(int argc, char** argv)
{
//加载图像
int cameraNumber = 0;
if (argc > 1){
cameraNumber = atoi(argv[1]);
}
//Get access to the camera
VideoCapture camera;
camera.open(cameraNumber);
if (!camera.isOpened()){
cerr << "ERROR : Could not access the camera or video!" << endl;
exit(1);
}
//Try to set the camera resolution
camera.set(CV_CAP_PROP_FRAME_WIDTH, 640);
camera.set(CV_CAP_PROP_FRAME_HEIGHT, 480);
while (true){
//Grab the next camera frame.
Mat cameraFrame;
camera >> cameraFrame;
if (cameraFrame.empty()){
cerr << "ERROR : Could not grab a camera frame!" << endl;
exit(1);
}
//Create a blank output image,that we will draw onto.
Mat displayedFrame(cameraFrame.size(), CV_8UC3);
//Run the cartoonfier filter on the camera frame.
//cartoonifyImage(cameraFrame, displayedFrame);//
//evilImage
evilImage(cameraFrame, displayedFrame);
//draw a face position
//facePosition(cameraFrame, displayedFrame);
//elienImage
//elienImage(cameraFrame, displayedFrame);
//Display the processed image onto the screen.
imshow("Cartoonifier", displayedFrame);
//IMPORTANT ; Wait for at least 20 milliseconds
//so that the image can be displayed on the screen!
//Also checks if a key was pressed in the GUI window.
//Note that it should be a "char" to support Linux.
char keypress = cv::waitKey(20); //Need this to see anything!
if (keypress == 27){//Escape Key
//Quit the program!
break;
}
}//end while
return 0;
}
/* cartoon.cpp */
#include "cartoon.h"
cartoon::cartoon()
{
}
cartoon::~cartoon()
{
}
void cartoonifyImage(Mat& srcColor,Mat& dst){
//素描图像
Mat gray;
cvtColor(srcColor, gray, CV_BGR2GRAY);
const int MEDIAN_BLUR_FILTER_SIZE = 7;
medianBlur(gray, gray, MEDIAN_BLUR_FILTER_SIZE);
Mat edges;
const int LAPLACIAN_FILTER_SIZE = 5;
Laplacian(gray, edges, CV_8U, LAPLACIAN_FILTER_SIZE);
//二值化阈值
Mat mask;
const int EDGES_THRESHOLD = 80;
threshold(edges, mask, EDGES_THRESHOLD, 255, THRESH_BINARY_INV);
//卡通画
Size size = srcColor.size();
Size smallSize;
smallSize.width = size.width / 2;
smallSize.height = size.height / 2;
Mat smallImg = Mat(smallSize, CV_8UC3);
resize(srcColor, smallImg, smallSize, 0, 0, INTER_LINEAR);
//双边滤波
Mat tmp = Mat(smallSize, CV_8UC3);
int repetitions = 7;//Repetitions for strong cartoon effect.
for (int i = 0; i < repetitions; i++){
int ksize = 9; //Filter size.Has a large effect on speed.
double sigmaColor = 9; //Filter color strength.
double sigmaSpace = 7; //Spatial strength.Affects speed.
bilateralFilter(smallImg, tmp, ksize, sigmaColor, sigmaSpace);
bilateralFilter(tmp, smallImg, ksize, sigmaColor, sigmaSpace);
}
//图像复原
Mat bigImg;
resize(smallImg, bigImg, size, 0, 0, INTER_LINEAR);
//Mat dst;
dst.setTo(0);
bigImg.copyTo(dst, mask);
}
void evilImage(Mat& srcColor, Mat& dst){
Mat srcGray;
cvtColor(srcColor, srcGray, CV_BGR2GRAY);
const int MEDIAN_BLUR_FILTER_SIZE = 7;
medianBlur(srcGray, srcGray, MEDIAN_BLUR_FILTER_SIZE);
Mat edges1, edges2;
Scharr(srcGray, edges1, CV_8U, 1, 0);
Scharr(srcGray, edges2, CV_8U, 1, 0, -1);
edges1 += edges2; //Combine the x&y edges together.
const int EVIL_EDGE_THRESHOLD = 12;
Mat mask1;
threshold(edges1, mask1, EVIL_EDGE_THRESHOLD, 255, THRESH_BINARY_INV);
medianBlur(mask1, mask1, 3);
//Mat dst1;
dst.setTo(0);
srcColor.copyTo(dst, mask1);
}
void facePosition(Mat& srcColor, Mat& dst){
Size size = srcColor.size();
//Draw the color face onto a black background.
Mat faceOutline = Mat::zeros(size, CV_8UC3);
Scalar color = CV_RGB(255, 255, 0); //Yellow
int thickness = 4;
//Use 70% of the screen height as the face height.
int sw = size.width;
int sh = size.height;
int faceH = sh / 2 * 70 / 100; //"faceH" is the radius of the ellipse.
//Scale the width to be the same shape for any screen width.
int faceW = faceH * 72 / 100;
//Draw the face outline.
ellipse(faceOutline, Point(sw / 2, sh / 2), Size(faceW, faceH), 0, 0, 360, color, thickness, CV_AA);
//Draw the eye outlines,as 2 arcs per eye.
int eyeW = faceW * 23 / 100;
int eyeH = faceW * 11 / 100;
int eyeX = faceW * 48 / 100;
int eyeY = faceW * 13 / 100;
Size eyeSize = Size(eyeW, eyeH);
//Set the angle and shift for the eye half ellipses.
int eyeA = 15;//angle in degrees.
int eyeYshift = 11;
//Draw the top of the right eye.
ellipse(faceOutline, Point(sw / 2 - eyeX, sh / 2 - eyeY), eyeSize, 0, 180 + eyeA, 360 - eyeA, color, thickness, CV_AA);
//Draw the bottom of the right eye.
ellipse(faceOutline, Point(sw / 2 - eyeX, sh / 2 - eyeY - eyeYshift), eyeSize, 0, 0 + eyeA, 180 - eyeA, color, thickness, CV_AA);
//Draw the top of the left eye.
ellipse(faceOutline, Point(sw / 2 + eyeX, sh / 2 - eyeY), eyeSize, 0, 180 + eyeA, 360 - eyeA, color, thickness, CV_AA);
//Draw the bottom of the left eye.
ellipse(faceOutline, Point(sw / 2 + eyeX, sh / 2 - eyeY - eyeYshift), eyeSize, 0, 0 + eyeA, 180 - eyeA, color, thickness, CV_AA);
//Draw the bottom lip of the mouth.
int mouthY = faceH * 48 / 100;
int mouthW = faceH * 45 / 100;
int mouthH = faceH * 6 / 100;
ellipse(faceOutline, Point(sw / 2, sh / 2 + mouthY), Size(mouthW, mouthH), 0, 0, 180, color, thickness, CV_AA);
//Draw anti-aliased text.
int fontFace = FONT_HERSHEY_COMPLEX;
float fontScale = 1.0f;
int fontThickness = 2;
char *szMsg = "Put your face here";
putText(faceOutline, szMsg, Point(sw * 23 / 100, sh * 10 / 100), fontFace, fontScale, color, fontThickness, CV_AA);
addWeighted(srcColor, 1.0, faceOutline, 0.7, 0, dst, CV_8UC3);
}
void elienImage(Mat& srcColor, Mat& dst){
//素描图像
Mat gray;
cvtColor(srcColor, gray, CV_BGR2GRAY);
const int MEDIAN_BLUR_FILTER_SIZE = 7;
medianBlur(gray, gray, MEDIAN_BLUR_FILTER_SIZE);
Mat edges;
const int LAPLACIAN_FILTER_SIZE = 5;
Laplacian(gray, edges, CV_8U, LAPLACIAN_FILTER_SIZE);
//缩小图像
Size size = srcColor.size();
Size smallSize;
smallSize.width = size.width / 2;
smallSize.height = size.height / 2;
Mat smallImg = Mat(smallSize, CV_8UC3);
resize(srcColor, smallImg, smallSize, 0, 0, INTER_LINEAR);
//彩图转成YUV格式
Mat yuv = Mat(smallSize, CV_8UC3);
cvtColor(smallImg, yuv, CV_BGR2YCrCb);
//dst = yuv;
int sw = smallSize.width;
int sh = smallSize.height;
Mat mask, maskPlusBorder;
maskPlusBorder = Mat::zeros(sh + 2, sw + 2, CV_8UC1);
mask = maskPlusBorder(Rect(1, 1, sw, sh));//mask is in maskPlusBorder.
resize(edges, mask, smallSize);//put edges in both of them.
//dst = maskPlusBorder;
//二值化阈值
const int EDGES_THRESHOLD = 80;
threshold(mask, mask, EDGES_THRESHOLD, 255, THRESH_BINARY);
dilate(mask, mask, Mat());
erode(mask, mask, Mat());
//在鼻子,脸颊和前额选择六个点,这些点的位置依赖于早期所确定的面部轮廓
//sw = size.width;
//sh = size.height;
int const NUM_SKIN_POINTS = 6;
Point skinPts[NUM_SKIN_POINTS];
skinPts[0] = Point(sw / 2, sh / 2 - sh / 6);
skinPts[1] = Point(sw / 2 - sw / 11, sh / 2 - sh / 6);
skinPts[2] = Point(sw / 2 + sw / 11, sh / 2 - sh / 6);
skinPts[3] = Point(sw / 2, sh / 2 - sh / 16);
skinPts[4] = Point(sw / 2 - sw / 9, sh / 2 - sh / 16);
skinPts[5] = Point(sw / 2 + sw / 9, sh / 2 - sh / 16);
const int LOWER_Y = 60;
const int UPPER_Y = 80;
const int LOWER_Cr = 25;
const int UPPER_Cr = 15;
const int LOWER_Cb = 20;
const int UPPER_Cb = 15;
Scalar lowerDiff = Scalar(LOWER_Y, LOWER_Cr, LOWER_Cb);
Scalar upperDiff = Scalar(UPPER_Y, UPPER_Cr, UPPER_Cb);
const int CONNECTED_COMPONENTS = 8;//To fill diagonally,use 8.
const int flags = CONNECTED_COMPONENTS | FLOODFILL_FIXED_RANGE | FLOODFILL_MASK_ONLY;
Mat edgeMask = mask.clone();//Keep a copy of the edge mask;
//"maskPlusBorder" is initialized with edges to block floodFill().
//imshow("test", mask);
for (int i = 0; i < NUM_SKIN_POINTS; i++){
floodFill(yuv, maskPlusBorder, skinPts[i], Scalar(), NULL, lowerDiff, upperDiff, flags);
//搞不出来,就是难受,非常难受TAT
}
dst = yuv;
}
/* cartoon.h */
#pragma once
//Include OpenCV's C++ Interface
#include "opencv2/opencv.hpp"
using namespace cv;
using namespace std;
class cartoon
{
public:
cartoon();
~cartoon();
};
void cartoonifyImage(Mat& srcColor,Mat& dst);
void evilImage(Mat& srcColor, Mat& dst);
void facePosition(Mat& srcColor, Mat& dst);
void elienImage(Mat& srcColor, Mat& dst);