Master opencv 學習筆記一

輸入一幅圖像,得到其素描(黑白圖畫)效果,將素描疊加到彩色圖像上,得到一種卡通效果。

顯示素描模式、卡通模式、外星人模式和怪物模式。


實驗代碼:

<span style="font-size:18px;">#include "cv.h"
#include "highgui.h"
#include "opencv.hpp"
#include "stdio.h"
#include "stdlib.h"

using namespace cv;
using namespace std;

const int NUM_STICK_FIGURE_ITERATIONS = 40;

void cartoonifyImage(Mat srcColor, Mat dst, bool sketchMode, bool alienMode, bool evilMode);
void changefacialcolor (Mat smallImg, Size smallsize, Mat edges);
void drawface(Mat dst,Size size);

int main(int argc,char *argv[])
{
	int cameraNumber = 0;
	int m_stickFigureIterations;
	if (argc > 1)
	cameraNumber = atoi(argv[1]);
	//get access to the camera
	cv::VideoCapture camera;
	//camera.open(cameraNumber);
	//video from file
	//camera.open("e:/test.avi");
	/*
	if (!camera.isOpened())
	{
		std::cerr << "ERROR: Could not access the camera or video!" << std::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);
	//read picture
	while (true)
	{
		//Grab the next camera frame;
		
		cv::Mat cameraFrame;
		/*
		camera >>cameraFrame;
		if (cameraFrame.empty())
		{
			std::cerr << "Error: couldn't grab a camera frame." << std::endl;
			exit(1);
		}
		*/
		// Create a blank output image, that we will draw onto.
		cameraFrame = imread("e:/lena.jpg");
		cv::Mat displayedFrame (cameraFrame.size(),CV_8UC3);
		
		//Run the cartoonifier filter on the camer frame.
		//cartoonifyImage(cameraFrame,displayedFrame);
		//cartoonifyImage( cameraFrame, displayedFrame, 1, 0, 0) ;// 顯示素描模式
		
		//cartoonifyImage( cameraFrame, displayedFrame, 0, 0, 1) ; //顯示怪物模式
		//cartoonifyImage( cameraFrame, displayedFrame, 0, 0, 0) ; //顯示卡通模式

		// Show a stick-figure outline of a face for a short duration, so the user knows where to put their face.
		m_stickFigureIterations = NUM_STICK_FIGURE_ITERATIONS;
		if (m_stickFigureIterations > 0) {
			Size size = displayedFrame.size();
			drawface(cameraFrame,size);
			m_stickFigureIterations--;
		}
		cartoonifyImage( cameraFrame, displayedFrame, 0, 1, 0) ;//顯示外星人模式
		//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(0);
		if ( keypress == 27)  // Escape key
		{
			break;// Quit the program!
		}
		
	} // end of while

	system("pause");
	return 0;

}


// Convert the given photo into a cartoon-like or painting-like image.
// Set sketchMode to true if you want a line drawing instead of a painting.
// Set alienMode to true if you want alien skin instead of human.
// Set evilMode to true if you want an "evil" character instead of a "good" character.
// Set cartoon mode to true if you want an cartoon-like image. 
// Set debugType to 1 to show where skin color is taken from, and 2 to show the skin mask in a new window (for desktop).
void cartoonifyImage(Mat srcColor, Mat dst, bool sketchMode, bool alienMode, bool evilMode)  //素描模式、外星人模式、怪物模式
{
	Mat gray;
	cvtColor(srcColor,gray,CV_BGR2GRAY);
	const int MEDIAN_BLUR_FILTER_SIZE = 7;
	medianBlur(gray,gray,MEDIAN_BLUR_FILTER_SIZE);
	Mat edges;
	Mat mask;
	dst.setTo(0);
	if (!evilMode)
	{
	const int LAPLACIAN_FILTER_SIZE = 5;
	Laplacian(gray,edges,CV_8U,LAPLACIAN_FILTER_SIZE);
	const int EDGES_THRESHOLD = 80;
	threshold(edges,mask,EDGES_THRESHOLD,255,THRESH_BINARY_INV);
	}
	else
	{
		Mat edges,edges2;
		Scharr(gray, edges, CV_8U, 1, 0);
		Scharr(gray, edges2, CV_8U, 1, 0, -1);
		edges += edges2; // Cobine the x & y edges together
		const int EVIL_EDGE_THRESHOLD = 12;
		threshold (edges, mask, EVIL_EDGE_THRESHOLD, 255, THRESH_BINARY_INV);
		medianBlur( mask, mask, 3);
		imshow("edge",edges);
		imshow("evilMask",mask); //怪物掩碼
		srcColor.copyTo(dst,mask);  //將掩碼疊加到原圖像上
		imshow("evilMode",dst);
		return;
	}

	if (sketchMode)
	{
		cvtColor(mask,dst,CV_GRAY2BGR);
		//imshow("sketch",mask);
		return;
	}
	
	// resize the src image
	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變量
	Mat temp = Mat (smallSize, CV_8UC3);
	int repetitions = 7;//Repretitions 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, temp, ksize, sigmaColor, sigmaSpace);
		bilateralFilter(temp, smallImg, ksize, sigmaColor, sigmaSpace);
	}

	if (alienMode)
	{
		 
		// Apply an "alien" filter, when given a shrunken image and the full-res edge mask.
		// Detects the color of the pixels in the middle of the image, then changes the color of that region to green.
		changefacialcolor(smallImg, smallSize, edges);

	}

	Mat bigImg;
	resize(smallImg, bigImg, size, 0, 0, INTER_LINEAR);
	bigImg.copyTo(dst,mask);
	//imshow("crtoon",dst);//顯示卡通模式(彩色圖像+素描掩碼)
	
}


//下列函數確定用戶放置臉位置
// Draw an anti-aliased face outline, so the user knows where to put their face.
// Note that the skin detector for "alien" mode uses points around the face based on the face
// dimensions shown by this function.
void drawface(Mat dst,Size 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 * 0.7;
	// Scalar the width to be the same for any screen width. 
	int faceW = faceH * 0.72;
	//Draw the faces 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 * 0.23;
	int eyeH = faceH * 0.11;
	int eyeX = faceW * 0.48;
	int eyeY = faceH * 0.13;
	Size eyeSize = Size (eyeW, eyeH);
	// set the angle and shift for the eye half ellipses.
	// 使用上橢圓作爲眼睛的上半部分,下橢圓作爲眼睛的下半部分。
	int eyeA = 15;  // angle in degress.
	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 left eye.
	ellipse(faceOutline,Point(sw/2 + eyeX, sh/2 - eyeY),eyeSize, 0, 180+eyeA, 360-eyeA, color, thickness, thickness,CV_AA);
	//draw the bottom 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 * 0.48;
	int mouthW = faceW * 0.45;
	int mouthH = faceH * 0.06;
	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 fontScalar = 1.0f;
	int fontThickness = 2;
	char *szMsg = "Put your face here";
	putText(faceOutline,szMsg,Point(sw * 0.23,sh * 0.1),fontFace, fontScalar,color,fontThickness,CV_AA);

	//利用alpha融合卡通圖像與人臉輪廓,dst是卡通處理後的圖像
	addWeighted(dst, 1.0, faceOutline, 0.7, 0, dst, CV_8UC3);
	imshow("臉輪廓",dst);

}


// Apply an "alien" filter, when given a shrunken BGR image and the full-res edge mask.
// Detects the color of the pixels in the middle of the image, then changes the color of that region to green.
void changefacialcolor (Mat smallImg, Size smallsize, Mat edges)
{
	//change rgb into yuv space.
	Mat yuv = Mat(smallsize,CV_8UC3);
	cvtColor(smallImg, yuv, CV_BGR2YCrCb);

	// The floodFill mask has to be 2 pixels wider and 2 pixels taller than the small image.
	// The edge mask is the full src image size, so we will shrink it to the small size,
	// storing into the floodFill mask data.
	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));
	resize(edges,mask,smallsize); //put edges in both of them.

	// Make the mask values just 0 or 255, to remove weak edges.
	const int EDGES_THRESHOLD = 80;
	threshold(mask,mask,EDGES_THRESHOLD,255,THRESH_BINARY);
	dilate(mask, mask, Mat());
	erode(mask, mask, Mat());

	int const NUM_SKIN_POINT = 6;
	Point skinPts[NUM_SKIN_POINT];
	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 = 4;//To fill diagonally, use 8.
	const int flags = CONNECTED_COMPONENTS | FLOODFILL_FIXED_RANGE| FLOODFILL_MASK_ONLY;
	Mat edegMask = mask.clone(); // keep a copy of the edge mask.
	// "maskPlusBorder" is initialized with edges to block floodFill().

	for ( int i = 0; i < NUM_SKIN_POINT; i++)
	{
		floodFill( yuv, maskPlusBorder, skinPts[i], Scalar(), NULL, lowerDiff, upperDiff, flags);
	}


	mask -= edegMask;
	int Red = 0;
	int Green = 70;
	int Blue = 0;
	add(smallImg, Scalar(Red,Green,Blue), smallImg, mask);
}
</span>



實驗結果:


素描模式


卡通模式


怪物模式


外星人模式


      這裏的外星人模式,因爲獲得人臉輪廓跟圖像有差異,導致圖像效果不對,應該能通過修改參數,調整。原程序主要是應用於攝像頭輸入圖片的。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章