OpenCV2学习笔记(十四):基于OpenCV卡通图片处理
得知OpenCV有一段時間。除了研究的各種算法的內(nèi)容。除了從備用,據(jù)導(dǎo)游書籍和資料,嘗試結(jié)合鏈接的圖像處理算法和日常生活,第一桌面上(隨著攝像頭)完成了一系列的視頻流處理功能。開發(fā)平臺Qt5.3.2+OpenCV2.4.9。
本次試驗實現(xiàn)的功能主要有:
本節(jié)全部的算法均由類cartoon中的函數(shù)cartoonTransform()來實現(xiàn):
// Frame:輸入每一幀圖像 output:輸出圖像 cartoonTransform(cv::Mat &Frame, cv::Mat &output)興許將使用很多其它的OpenCV技巧實現(xiàn)很多其它功能,并將該應(yīng)用移植到Android系統(tǒng)上。
一、使用OpenCV訪問攝像頭
OpenCV提供了一個簡便易用的框架以提取視頻文件和USB攝像頭中的圖像幀。假設(shè)你僅僅是想讀取某個視頻,你僅僅須要創(chuàng)建一個cv::VideoCapture實例,然后在循環(huán)中提取每一幀。這里須要訪問攝像頭,因此須要創(chuàng)建一個cv::VideoCapture對象,簡單調(diào)用對象的open()方法。這里訪問攝像頭的函數(shù)例如以下,首先在Qt中創(chuàng)建控制臺項目。在main函數(shù)中加入:
int cameraNumber = 0; // 設(shè)定攝像頭編號為0if(argc > 1)cameraNumber = atoi(argv[1]);// 開啟攝像頭cv::VideoCapture camera;camera.open(cameraNumber);if(!camera.isOpened()){qDebug() << "Error: Could not open the camera.";exit(1);}// 調(diào)整攝像頭的輸出分辨率camera.set(CV_CAP_PROP_FRAME_WIDTH, 640);camera.set(CV_CAP_PROP_FRAME_HEIGHT, 480);在攝像頭被初始化后,能夠使用C++流運算符將cv::VideoCapture對象轉(zhuǎn)換成cv::Mat對象,這樣能夠獲取視頻的每一幀圖像。
關(guān)于視頻流讀取可參考: http://blog.csdn.net/liyuefeilong/article/details/44066097
二、將幀圖像轉(zhuǎn)換為素描效果圖片
要將一幅圖像轉(zhuǎn)換為素描效果圖,能夠使用不同的邊緣檢測算法實現(xiàn)。如經(jīng)常使用的基于Sobel、Canny、Robert、Prewitt、Laplacian等算子的濾波器均能夠?qū)崿F(xiàn)這一操作,但處理效果各異。
1.Sobel算子:邊緣檢測中最經(jīng)常使用的一種方法,在技術(shù)上它是以離散型的差分算子,用來運算圖像亮度函數(shù)的梯度的近似值,缺點是Sobel算子并沒有將圖像的主題與背景嚴(yán)格地區(qū)分開來,換言之就是Sobel算子并沒有基于圖像灰度進行處理,因為Sobel算子并沒有嚴(yán)格地模擬人的視覺生理特征,所以提取的圖像輪廓有時并不能令人愜意。
2.Robert算子:依據(jù)任一相互垂直方向上的差分都用來預(yù)計梯度。Robert算子採用對角方向相鄰像素之差。
3.Prewitt算子:該算子與Sobel算子相似。僅僅是權(quán)值有所變化,但兩者實現(xiàn)起來功能還是有差距的,據(jù)經(jīng)驗得知Sobel要比Prewitt更能準(zhǔn)確檢測圖像邊緣。
4.Laplacian算子:該算子是一種二階微分算子,若僅僅考慮邊緣點的位置而不考慮周圍的灰度差時可用該算子進行檢測。
對于階躍狀邊緣。其二階導(dǎo)數(shù)在邊緣點出現(xiàn)零交叉,并且邊緣點兩旁的像素的二階導(dǎo)數(shù)異號。
5.Canny算子:該算子的基本性能比前面幾種要好。可是相對來說算法復(fù)雜。
Canny算子是一個具有濾波。增強,檢測的多階段的優(yōu)化算子。在進行處理前。Canny算子先利用高斯平滑濾波器來平滑圖像以除去噪聲,Canny切割算法採用一階偏導(dǎo)的有限差分來計算梯度幅值和方向,在處理過程中。Canny算子還將經(jīng)過一個非極大值抑制的過程。最后Canny算子還採用兩個閾值來連接邊緣。
相比Sobel等其它算子。Canny和Laplacian算子能得到更清晰的素描效果,而Laplacian的噪聲抑制要優(yōu)于Canny邊緣檢測,而其實素描邊緣在不同幀之間經(jīng)常有劇烈的變化,因此我們選擇Laplacian邊緣濾波器進行圖像處理。
一般在進行Laplacian檢測之前,須要對圖像進行的預(yù)操作有:
生成的素描效果:
三、將圖像卡通化
在項目中調(diào)用一些運算量大的算法時,通常須要考慮到效率問題,比方這里將要用到的雙邊濾波器。
這里我們利用雙邊濾波器的平滑區(qū)域及保持邊緣銳化的特性,將其運用到卡通圖片效果生成中。
而考慮到雙邊濾波器執(zhí)行效率較低,因此考慮在更低的分辨率中使用,這對效果影響不大,可是執(zhí)行速度大大加快。
這里使用的策略是將要處理的圖像的寬度和高度縮小為原來的1/2。經(jīng)過雙邊濾波器處理后,再將其恢復(fù)為原來的尺寸。在函數(shù)cartoonTransform()中加入下面代碼:
// 採用雙邊濾波器// 因為算法復(fù)雜,因此需降低圖像尺寸cv::Size size = Frame.size();cv::Size reduceSize;reduceSize.width = size.width / 2;reduceSize.height = size.height / 2;cv::Mat reduceImage = cv::Mat(reduceSize, CV_8UC3);cv::resize(Frame, reduceImage, reduceSize);// 雙邊濾波器實現(xiàn)過程cv::Mat tmp = cv::Mat(reduceSize, CV_8UC3);int repetitions = 7;for (int i=0 ; i < repetitions; i++){int kernelSize = 9;double sigmaColor = 9;double sigmaSpace = 7;cv::bilateralFilter(reduceImage, tmp, kernelSize, sigmaColor, sigmaSpace);cv::bilateralFilter(tmp, reduceImage, kernelSize, sigmaColor, sigmaSpace);}// 因為圖像是縮小后的圖像。須要恢復(fù)cv::Mat magnifyImage;cv::resize(reduceImage, magnifyImage, size);為了得到更好的效果。在以上代碼中加入下面函數(shù)。將恢復(fù)尺寸后的圖像與上一部分的素描結(jié)果相疊加。得到卡通版的圖像~~
cv::Mat dst;dst.setTo(0);magnifyImage.copyTo(dst, Binaryzation);//output = dst; //輸出卡通效果,閾值各方面有待優(yōu)化:
四、簡單地生成“怪物”形象
這里是結(jié)合了邊緣濾波器和中值濾波器的還有一個小應(yīng)用。即通過小的邊緣濾波器找到圖像中的各處邊緣。之后使用中值濾波器來合并這些邊緣。具體實現(xiàn)過程例如以下:
具體代碼例如以下,相同在函數(shù)cartoonTransform()中加入:
// 怪物模式cv::Mat gray ,maskMonster;cv::cvtColor(Frame, gray, CV_BGR2GRAY);// 先對輸入幀進行中值濾波cv::medianBlur(gray, gray, 7);// Scharr濾波器cv::Mat edge1, edge2;cv::Scharr(gray, edge1, CV_8U, 1, 0);cv::Scharr(gray, edge2, CV_8U, 1, 0, -1);edge1 += edge2; // 合并x和y方向的邊緣cv::threshold(edge1, maskMonster, 12, 255, cv::THRESH_BINARY_INV);cv::medianBlur(maskMonster, maskMonster, 3);output = maskMonster; //輸出五、人臉膚色變換
皮膚檢測算法有非常多種,比方基于RGB color space、Ycrcb之cr分量+otsu閾值化、基于混合模型的復(fù)雜機器學(xué)習(xí)算法等。
因為這里僅僅是一個輕量級的應(yīng)用,因此不考慮使用太復(fù)雜的算法。
考慮到未來要將這些圖像處理算法移植到安卓上,而移動設(shè)備上的微型攝像頭傳感器對顏色的反應(yīng)往往差異非常大,并且要在沒有標(biāo)定的情況下對不同膚色的人進行皮膚檢測,因此對算法的魯棒性要求較高。
這里使用了一個技巧,即在圖像中規(guī)定一個區(qū)域,用戶須要將臉部放到指定區(qū)域中來確定人臉在圖像中的位置(其實有些手機應(yīng)用也會採取這樣的方法),對于移動設(shè)備來說這不是一件難事。
因此,我們須要規(guī)定人臉的區(qū)域,相同在函數(shù)cartoonTransform()中加入下面代碼:
// 怪物模式cv::Mat gray ,maskMonster;cv::cvtColor(Frame, gray, CV_BGR2GRAY);// 先對輸入幀進行中值濾波cv::medianBlur(gray, gray, 7);// Scharr濾波器cv::Mat edge1, edge2;cv::Scharr(gray, edge1, CV_8U, 1, 0);cv::Scharr(gray, edge2, CV_8U, 1, 0, -1);edge1 += edge2; // 合并x和y方向的邊緣cv::threshold(edge1, maskMonster, 12, 255, cv::THRESH_BINARY_INV);cv::medianBlur(maskMonster, maskMonster, 3);output = maskMonster; //輸出// 換膚模式// 繪制臉部區(qū)域cv::Mat faceFrame = cv::Mat::zeros(size, CV_8UC3);cv::Scalar color = CV_RGB(128, 0, 128); // 顏色int thickness = 4;// 使之占整個圖像高度的70%int width = size.width;int height = size.height;int faceHeight = height/2 * 70/100;int faceWidth = faceHeight * 72/100;cv::ellipse(faceFrame, cv::Point(width/2, height/2), cv::Size(faceWidth, faceHeight),0, 0, 360, color, thickness, CV_AA);// imshow("test3", faceFrame);// 繪制眼睛區(qū)域int eyeHeight = faceHeight * 11/100;int eyeWidth = faceWidth * 23/100;int eyeY = faceHeight * 13/100;int eyeX = faceWidth * 48/100;cv::Size eyeSize = cv::Size(eyeWidth, eyeHeight);int eyeAngle = 15; //角度int eyeYShift = 11;// 畫右眼的上眼皮cv::ellipse(faceFrame, cv::Point(width/2 - eyeX, height/2 - eyeY),eyeSize, 0, 180+eyeAngle, 360-eyeAngle, color, thickness, CV_AA);// 畫右眼的下眼皮cv::ellipse(faceFrame, cv::Point(width/2 - eyeX, height/2 - eyeY - eyeYShift),eyeSize, 0, 0+eyeAngle, 180-eyeAngle, color, thickness, CV_AA);// 畫左眼的上眼皮cv::ellipse(faceFrame, cv::Point(width/2 + eyeX, height/2 - eyeY),eyeSize, 0, 180+eyeAngle, 360-eyeAngle, color, thickness, CV_AA);// 畫左眼的下眼皮cv::ellipse(faceFrame, cv::Point(width/2 + eyeX, height/2 - eyeY - eyeYShift),eyeSize, 0, 0+eyeAngle, 180-eyeAngle, color, thickness, CV_AA);char *Message = "Put your face here";cv::putText(faceFrame, Message, cv::Point(width * 13/100, height * 10/100),cv::FONT_HERSHEY_COMPLEX,1.0f,color,2,CV_AA);cv::addWeighted(dst, 1.0, faceFrame, 0.7, 0, dst, CV_8UC3);//output = dst;效果:
皮膚變色器的實現(xiàn)基于OpenCV的floodFill()函數(shù),該函數(shù)相似于一些畫圖軟件中的顏料桶(顏色填充)工具。 因為規(guī)定屏幕中間橢圓區(qū)域就是皮膚像素,因此僅僅須要對該區(qū)域的像素進行各種顏色的漫水填充就可以。
這里處理的圖像是彩色圖,而對于RGB格式的圖像,改變顏色的效果不會太好,因為改變顏色須要臉部圖像的亮度變化,而皮膚顏色也不能變化太大。這里使用YCrCb顏色空間來進行處理。在YCrCb顏色空間中,能夠直接獲得亮度值,并且通常的皮膚顏色取值唯一。
// 皮膚變色器cv::Mat YUVImage = cv::Mat(reduceSize, CV_8UC3);cv::cvtColor(reduceImage, YUVImage, CV_BGR2YCrCb);int sw = reduceSize.width;int sh = reduceSize.height;cv::Mat mask, maskPlusBorder;maskPlusBorder = cv::Mat::zeros(sh+2, sw+2, CV_8UC1);mask = maskPlusBorder(cv::Rect(1, 1, sw, sh));cv::resize(edge, mask, reduceSize);const int EDGES_THRESHOLD = 80;cv::threshold(mask, mask, EDGES_THRESHOLD, 255, cv::THRESH_BINARY);cv::dilate(mask, mask, cv::Mat());cv::erode(mask, mask, cv::Mat());// output = mask;// 創(chuàng)建6個點進行漫水填充算法cv::Point skinPoint[6];skinPoint[0] = cv::Point(sw/2, sh/2 - sh/6);skinPoint[1] = cv::Point(sw/2 - sw/11, sh/2 - sh/6);skinPoint[2] = cv::Point(sw/2 + sw/11, sh/2 - sh/6);skinPoint[3] = cv::Point(sw/2, sh/2 + sh/6);skinPoint[4] = cv::Point(sw/2 - sw/9, sh/2 + sh/6);skinPoint[5] = cv::Point(sw/2 + sw/9, sh/2 + sh/6);// 設(shè)定漫水填充算法的上下限const int MIN_Y = 60;const int MAX_Y = 80;const int MIN_Cr = 25;const int MAX_Cr = 15;const int MIN_Cb = 20;const int MAX_Cb = 15;cv::Scalar Min = cv::Scalar(MIN_Y, MIN_Cr, MIN_Cb);cv::Scalar Max = cv::Scalar(MAX_Y, MAX_Cr, MAX_Cb);// 調(diào)用漫水填充算法const int CONNECTED_COMPONENTS = 4;const int flag = CONNECTED_COMPONENTS | cv::FLOODFILL_FIXED_RANGE \| cv::FLOODFILL_MASK_ONLY;cv::Mat edgeMask = mask.clone();//for(int i = 0; i < 6; i++){cv::floodFill(YUVImage, maskPlusBorder, skinPoint[i], cv::Scalar(), NULL,Min, Max, flag);}cv::Mat BGRImage;cv::cvtColor(YUVImage, BGRImage, CV_YCrCb2BGR);mask -= edgeMask;int Red = 0;int Green = 70;int Blue = 0;cv::Scalar color2 = CV_RGB(Red, Green, Blue); // 顏色cv::add(BGRImage, color2, BGRImage, mask);cv::Mat tt;cv::resize(BGRImage, tt, size);cv::add(dst, tt ,dst);output = dst; // 換膚結(jié)果因為在臉部區(qū)域中要對很多像素使用漫水填充算法,因此為了保證人臉圖像的各種顏色和陰影都能得到處理,這里設(shè)置了前額、鼻子和臉頰6個點。他們的定位依賴于先前規(guī)定的臉部輪廓坐標(biāo)。輸出效果例如以下:
臉部不在識別區(qū)域內(nèi)時:
臉部進入識別區(qū)域內(nèi)時:
以上實現(xiàn)了幾種圖片卡通化效果,接著在學(xué)有余力時要對各種算法的效果進行優(yōu)化。同一時候加入GUI界面,并將應(yīng)用移植到移動設(shè)備上。
參考資料:《深入理解OpenCV:有用計算機視覺項目解析》
完整代碼:
cartoon.h:
#ifndef CARTOON_H #define CARTOON_H #include <opencv2/core/core.hpp> #include <opencv2/imgproc/imgproc.hpp> #include <opencv2/highgui/highgui.hpp>class cartoon { public:void cartoonTransform(cv::Mat &Frame, cv::Mat &output); };#endif // CARTOON_Hcartoon.cpp:
#include "cartoon.h"void cartoon::cartoonTransform(cv::Mat &Frame, cv::Mat &output) {cv::Mat grayImage;cv::cvtColor(Frame, grayImage, CV_BGR2GRAY);// 設(shè)置中值濾波器參數(shù)cv::medianBlur(grayImage, grayImage, 7);// Laplacian邊緣檢測cv::Mat edge; // 用于存放邊緣檢測輸出結(jié)果cv::Laplacian(grayImage, edge, CV_8U, 5);// 對邊緣檢測結(jié)果進行二值化cv::Mat Binaryzation; // 用于存放二值化輸出結(jié)果cv::threshold(edge, Binaryzation, 80, 255, cv::THRESH_BINARY_INV);// 下面操作生成彩色圖像和卡通效果// 採用雙邊濾波器// 因為算法復(fù)雜,因此需降低圖像尺寸cv::Size size = Frame.size();cv::Size reduceSize;reduceSize.width = size.width / 2;reduceSize.height = size.height / 2;cv::Mat reduceImage = cv::Mat(reduceSize, CV_8UC3);cv::resize(Frame, reduceImage, reduceSize);// 雙邊濾波器實現(xiàn)過程cv::Mat tmp = cv::Mat(reduceSize, CV_8UC3);int repetitions = 7;for (int i=0 ; i < repetitions; i++){int kernelSize = 9;double sigmaColor = 9;double sigmaSpace = 7;cv::bilateralFilter(reduceImage, tmp, kernelSize, sigmaColor, sigmaSpace);cv::bilateralFilter(tmp, reduceImage, kernelSize, sigmaColor, sigmaSpace);}// 因為圖像是縮小后的圖像,須要恢復(fù)cv::Mat magnifyImage;cv::resize(reduceImage, magnifyImage, size);cv::Mat dst;dst.setTo(0);magnifyImage.copyTo(dst, Binaryzation);//output = dst; //輸出// 怪物模式cv::Mat gray ,maskMonster;cv::cvtColor(Frame, gray, CV_BGR2GRAY);// 先對輸入幀進行中值濾波cv::medianBlur(gray, gray, 7);// Scharr濾波器cv::Mat edge1, edge2;cv::Scharr(gray, edge1, CV_8U, 1, 0);cv::Scharr(gray, edge2, CV_8U, 1, 0, -1);edge1 += edge2; // 合并x和y方向的邊緣cv::threshold(edge1, maskMonster, 12, 255, cv::THRESH_BINARY_INV);cv::medianBlur(maskMonster, maskMonster, 3);output = maskMonster; //輸出// 換膚模式// 繪制臉部區(qū)域cv::Mat faceFrame = cv::Mat::zeros(size, CV_8UC3);cv::Scalar color = CV_RGB(128, 0, 128); // 顏色int thickness = 4;// 使之占整個圖像高度的70%int width = size.width;int height = size.height;int faceHeight = height/2 * 70/100;int faceWidth = faceHeight * 72/100;cv::ellipse(faceFrame, cv::Point(width/2, height/2), cv::Size(faceWidth, faceHeight),0, 0, 360, color, thickness, CV_AA);// imshow("test3", faceFrame);// 繪制眼睛區(qū)域int eyeHeight = faceHeight * 11/100;int eyeWidth = faceWidth * 23/100;int eyeY = faceHeight * 13/100;int eyeX = faceWidth * 48/100;cv::Size eyeSize = cv::Size(eyeWidth, eyeHeight);int eyeAngle = 15; //角度int eyeYShift = 11;// 畫右眼的上眼皮cv::ellipse(faceFrame, cv::Point(width/2 - eyeX, height/2 - eyeY),eyeSize, 0, 180+eyeAngle, 360-eyeAngle, color, thickness, CV_AA);// 畫右眼的下眼皮cv::ellipse(faceFrame, cv::Point(width/2 - eyeX, height/2 - eyeY - eyeYShift),eyeSize, 0, 0+eyeAngle, 180-eyeAngle, color, thickness, CV_AA);// 畫左眼的上眼皮cv::ellipse(faceFrame, cv::Point(width/2 + eyeX, height/2 - eyeY),eyeSize, 0, 180+eyeAngle, 360-eyeAngle, color, thickness, CV_AA);// 畫左眼的下眼皮cv::ellipse(faceFrame, cv::Point(width/2 + eyeX, height/2 - eyeY - eyeYShift),eyeSize, 0, 0+eyeAngle, 180-eyeAngle, color, thickness, CV_AA);char *Message = "Put your face here";cv::putText(faceFrame, Message, cv::Point(width * 13/100, height * 10/100),cv::FONT_HERSHEY_COMPLEX,1.0f,color,2,CV_AA);cv::addWeighted(dst, 1.0, faceFrame, 0.7, 0, dst, CV_8UC3);//output = dst;// 皮膚變色器cv::Mat YUVImage = cv::Mat(reduceSize, CV_8UC3);cv::cvtColor(reduceImage, YUVImage, CV_BGR2YCrCb);int sw = reduceSize.width;int sh = reduceSize.height;cv::Mat mask, maskPlusBorder;maskPlusBorder = cv::Mat::zeros(sh+2, sw+2, CV_8UC1);mask = maskPlusBorder(cv::Rect(1, 1, sw, sh));cv::resize(edge, mask, reduceSize);const int EDGES_THRESHOLD = 80;cv::threshold(mask, mask, EDGES_THRESHOLD, 255, cv::THRESH_BINARY);cv::dilate(mask, mask, cv::Mat());cv::erode(mask, mask, cv::Mat());// output = mask;// 創(chuàng)建6個點進行漫水填充算法cv::Point skinPoint[6];skinPoint[0] = cv::Point(sw/2, sh/2 - sh/6);skinPoint[1] = cv::Point(sw/2 - sw/11, sh/2 - sh/6);skinPoint[2] = cv::Point(sw/2 + sw/11, sh/2 - sh/6);skinPoint[3] = cv::Point(sw/2, sh/2 + sh/6);skinPoint[4] = cv::Point(sw/2 - sw/9, sh/2 + sh/6);skinPoint[5] = cv::Point(sw/2 + sw/9, sh/2 + sh/6);// 設(shè)定漫水填充算法的上下限const int MIN_Y = 60;const int MAX_Y = 80;const int MIN_Cr = 25;const int MAX_Cr = 15;const int MIN_Cb = 20;const int MAX_Cb = 15;cv::Scalar Min = cv::Scalar(MIN_Y, MIN_Cr, MIN_Cb);cv::Scalar Max = cv::Scalar(MAX_Y, MAX_Cr, MAX_Cb);// 調(diào)用漫水填充算法const int CONNECTED_COMPONENTS = 4;const int flag = CONNECTED_COMPONENTS | cv::FLOODFILL_FIXED_RANGE \| cv::FLOODFILL_MASK_ONLY;cv::Mat edgeMask = mask.clone();//for(int i = 0; i < 6; i++){cv::floodFill(YUVImage, maskPlusBorder, skinPoint[i], cv::Scalar(), NULL,Min, Max, flag);}cv::Mat BGRImage;cv::cvtColor(YUVImage, BGRImage, CV_YCrCb2BGR);mask -= edgeMask;int Red = 0;int Green = 70;int Blue = 0;cv::Scalar color2 = CV_RGB(Red, Green, Blue); // 顏色cv::add(BGRImage, color2, BGRImage, mask);cv::Mat tt;cv::resize(BGRImage, tt, size);cv::add(dst, tt ,dst);output = dst; // 換膚結(jié)果 }main函數(shù):
#include "cartoon.h" #include <QApplication> #include <QDebug> #include <opencv2/video/video.hpp>int main(int argc, char *argv[]) {QApplication a(argc, argv);cartoon photo;int cameraNumber = 0;if(argc > 1)cameraNumber = atoi(argv[1]);// 開啟攝像頭cv::VideoCapture camera;camera.open(cameraNumber);if(!camera.isOpened()){qDebug() << "Error: Could not open the camera.";exit(1);}// 調(diào)整攝像頭的分辨率camera.set(CV_CAP_PROP_FRAME_WIDTH, 640);camera.set(CV_CAP_PROP_FRAME_HEIGHT, 480);while (1){cv::Mat Frame;camera >> Frame;if(!Frame.data){qDebug() << "Couldn't capture camera frame.";exit(1);}// 創(chuàng)建一個用于存放輸出圖像的數(shù)據(jù)結(jié)構(gòu)cv::Mat output(Frame.size(), CV_8UC3);photo.cartoonTransform(Frame, output);// 使用圖像處理技術(shù)將獲取的幀經(jīng)過處理后輸入到output中cv::imshow("Original", Frame);cv::imshow("Carton", output);char keypress = cv::waitKey(20);if(keypress == 27){break;}}return a.exec(); }版權(quán)聲明:本文博主原創(chuàng)文章。博客,未經(jīng)同意不得轉(zhuǎn)載。
轉(zhuǎn)載于:https://www.cnblogs.com/zfyouxi/p/4838928.html
總結(jié)
以上是生活随笔為你收集整理的OpenCV2学习笔记(十四):基于OpenCV卡通图片处理的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Sql-事务
- 下一篇: initWithFrame方法的理解(转