opencv學習系列:例項練習(含多個例項)
阿新 • • 發佈:2019-02-14
//-----------------------------------OpenCV學習-------------------------------------
// 程式名稱:OpenCV程式模板樣式
// 所用IDE版本: Visual Studio 2013
// 開發所用OpenCV版本: 2.4.9
// 2016年10月 Created by 孫立波
//包含程式所依賴的標頭檔案:為方便起見把經常用的標頭檔案都寫在這裡(前三必須包含),也可以用#include "opencv.hpp"包含下面所有標頭檔案
#include <opencv2\core\core.hpp> //程式庫核心功能,基本資料與結構和演算法函式
#include <opencv2\imgproc\imgproc.hpp> //包含主要的影象處理函式
#include <opencv2\highgui\highgui.hpp> //包含影象、視訊讀寫函式和部分使用者介面函式
//出現#include "cv.h"表示老式風格,幷包含老式所有標頭檔案
//#include <opencv2\features2d\features2d.hpp> //包含特徵點檢測器、描述子及特徵點匹配框架
//#include <opencv2\nonfree\nonfree.hpp> //SURF和SIFT會用到
#include <iostream>
//包含程式所使用的名稱空間
using namespace cv; //opencv2的名字空間
using namespace std;
//描述:控制檯應用程式的入口函式,程式從這裡開始執行??
int main(int argc, char** argv) //argv相當於"行"指標
{
return 0;
}
//-----------------------------------OpenCV學習1-------------------------------------
// 程式名稱:測試讀入圖片並顯示
// 2016年10月 Created by孫立波(Visual Studio 2013+OpenCV2.4.9)
#include <opencv2\opencv.hpp>
#include <iostream>
#include <string>
using namespace cv;
using namespace std;
int main()
{
Mat img = imread("D:\\workplace\\opencv_training\\test1.png");
if (img.empty())
{
cout << "error";
return -1; //除錯程式框會顯示返回值結果
}
imshow("mytest1", img);
waitKey(); //只有前面生成GUI視窗,waitKey才起作用
//如果前面執行失敗,還想看控制檯視窗輸出,可以在return前system("pause");
return 0;
}
//-----------------------------------OpenCV學習2-------------------------------------
// 程式名稱:用老版的OpenCV1測試讀入圖片並顯示
// 2016年10月 Created by孫立波(Visual Studio 2013+OpenCV2.4.9)
#include <cv.h>
#include <highgui.h>
using namespace std;
int main()
{
IplImage * test;
test = cvLoadImage("D:\\workplace\\opencv_training\\test1.png");//圖片路徑
cvNamedWindow("mytest1", 1);
cvShowImage("mytest1", test);
cvWaitKey(0);
cvDestroyWindow("mytest1");
cvReleaseImage(&test); //因為是用new動態生成的靜態記憶體空間
return 0;
}
//-----------------------------------OpenCV學習3-------------------------------------
// 程式名稱:翻轉圖片並顯示和儲存
// 2016年10月 Created by孫立波(Visual Studio 2013+OpenCV2.4.9)
#include <opencv2\opencv.hpp>
#include <iostream>
#include <string>
using namespace cv;
using namespace std;
int main()
{
Mat img1 = imread("D:\\workplace\\opencv_training\\test1.png");
if (img1.empty())
{
cout << "error:影象未裝載成功";
system("pause");
return -1; //除錯程式框會顯示返回值結果
}
imshow("mytest1", img1);
Mat img2;
flip(img1,img2,1);//正數表示水平,0表示垂直,負數表示水平和垂直都翻轉
imshow("mytest2", img2);
waitKey(0); //只有前面生成GUI視窗,waitKey才起作用
//如果前面執行失敗,還想看控制檯視窗輸出,可以在return前system("pause");
imwrite("output.bmp",img2);//儲存翻轉後的影象,再如imwrite("D:\\output.bmp",img2);
return 0;
}
//-----------------------------------OpenCV學習4-------------------------------------
// 程式名稱:翻轉圖片寫入原記憶體,並以讀入轉化方式生成灰度和彩色影象分別顯示
// 2016年10月 Created by孫立波(Visual Studio 2013+OpenCV2.4.9)
#include <opencv2\opencv.hpp>
#include <iostream>
#include <string>
using namespace cv;
using namespace std;
int main()
{
Mat img1 = imread("D:\\workplace\\opencv_training\\test1.png");
if (img1.empty())
{
cout << "error:影象未裝載成功";
system("pause");//使控制檯介面保留
return -1; //除錯程式框會顯示返回值結果
}
imshow("mytest1", img1);
Mat img2;
flip(img1,img1,1);//翻轉結果給原記憶體,正數表示水平,0表示垂直,負數表示水平和垂直都翻轉
imshow("mytest2", img1);
//得到原影象的灰度影象,巨集定義值為0,注:負數或不填寫即為原格式輸入到記憶體
Mat img3 = imread("D:\\workplace\\opencv_training\\test1.png",CV_LOAD_IMAGE_GRAYSCALE);
//得到原影象的彩色影象,巨集定義值為1
Mat img4 = imread("D:\\workplace\\opencv_training\\test1.png",CV_LOAD_IMAGE_COLOR);
imshow("mytest3", img3);
imshow("mytest4", img4);
waitKey(0); //只有前面生成GUI視窗,waitKey才起作用
//如果前面執行失敗,還想看控制檯視窗輸出,可以在return前system("pause");
return 0;
}
//-----------------------------------OpenCV學習5-------------------------------------
// 程式名稱:用cv開頭可以節省時間,深入瞭解Mat資料型別相關用法
// 2016年10月 Created by孫立波(Visual Studio 2013+OpenCV2.4.9)
// 複製建構函式和賦值運算子只會賦值Mat的頭部,copyTo和clone是深複製
// 不同資料型別Mat的複製用convertTo(通道數必須相同)
// create方法要看是否與原來的大小和型別相同來決定是否重分配資料塊
#include <opencv2\opencv.hpp>
#include <iostream>
#include <string>
using namespace cv;
using namespace std;
// 測試函式用於在記憶體返回一個自建立大小500*500、畫素值50的灰度值影象
Mat function()
{
// 用建構函式create image
Mat ima(500, 500, CV_8U, 50);
// return it
return ima;
}
int main()
{
// 建立一個240*320的值都為100的灰度影象並顯示,觀察效果後執行下一步程式
Mat image1(240, 320, CV_8U, 100);
// or:Mat image1(240,320,CV_8U,cv::Scalar(100));
imshow("Image0", image1);
waitKey(0);
// create方法要看是否與原來的大小和型別相同來決定是否重分配資料塊,例項:
// 用create方法重建一個大小和值不同的灰度影象,並顯示,觀察效果後執行下一步程式
image1.create(200, 200, CV_8U);
image1 = 200;
imshow("Image00", image1);
waitKey(0);
// 用建構函式建立一個紅色的彩色影象,大小為240*320,並顯示,觀察效果後執行下一步程式
Mat image2(240, 320, CV_8UC3, cv::Scalar(0, 0, 255));
// or:Mat image2(Size(320,240),CV_8UC3);image2= Scalar(0,0,255);
imshow("Image2", image2);
waitKey(0);
// 讀取影象用法!!
Mat image= imread("D:\\workplace\\opencv_training\\test1.png");
Mat image3;
image.copyTo(image3);
Mat image4 = image.clone();
//顯示源影象的拷貝與複製的影象,觀察效果後執行下一步程式
imshow("Image 3", image3);
imshow("Image 4", image4);
waitKey(0);
// 從程式定義的影象建立函式法獲取一個灰度影象,500*500畫素,觀察效果後執行下一步程式
Mat gray = function();
imshow("Image 5", gray);
waitKey(0);
//讀取一個原影象以灰度影象給記憶體,在資料型別不一樣情況下,用convertTo方法,觀察效果
Mat image5= imread("D:\\workplace\\opencv_training\\test1.png", CV_LOAD_IMAGE_GRAYSCALE);
// convert the image into a floating point image [0,1]浮點型影象
Mat image6;
image5.convertTo(image6, CV_32F, 1 / 255.0, 0.0);
imshow("Image 6", image6);
waitKey(0);
return 0;
}
//-----------------------------------OpenCV學習6-------------------------------------
// 程式名稱:ROI設定和掩碼操作例項
// 2016年10月 Created by孫立波(Visual Studio 2013+OpenCV2.4.9)
#include <opencv2\opencv.hpp>
#include <iostream>
#include <string>
using namespace cv;
using namespace std;
int main()
{
cv::Mat image = cv::imread("D:\\workplace\\opencv_training\\test2.png");
// read the logo
cv::Mat logo = cv::imread("D:\\workplace\\opencv_training\\test1.png");
// 以左上角為位置起點,構建原影象中資料區的logo對映區
cv::Mat imageROI(image,
cv::Rect(image.cols - logo.cols, //ROI coordinates
image.rows - logo.rows,
logo.cols, logo.rows));// ROI size
// 在ROI區域插入logo畫素值
logo.copyTo(imageROI);
cv::imshow("Image", image);
cv::waitKey(0); // wait for a key pressed
// re-read the original image注意此時影象是未處理的原影象無ROI
image = cv::imread("D:\\workplace\\opencv_training\\test2.png");
// define image ROI at image bottom-right
imageROI = image(cv::Rect(image.cols - logo.cols, image.rows - logo.rows,
logo.cols, logo.rows));
// or using ranges:
// imageROI= image(cv::Range(image.rows-logo.rows,image.rows),
// cv::Range(image.cols-logo.cols,image.cols));
// use the logo as a mask (must be gray-level)將logo做掩碼其中掩碼畫素值為零的複製不到ROI
cv::Mat mask1(logo);
// insert by copying only at locations of non-zero mask
logo.copyTo(imageROI, mask1);
cv::imshow("Image1", image); // show the image
cv::waitKey(0); // wait for a key pressed
//讓掩碼影象即logo值全為0,檢視結果影象
logo = 0;
image = cv::imread("D:\\workplace\\opencv_training\\test2.png");
imageROI = image(cv::Rect(image.cols - logo.cols, image.rows - logo.rows,
logo.cols, logo.rows));
cv::Mat mask2(logo);
logo.copyTo(imageROI, mask2);
cv::imshow("Image2", image); // 結果應顯示,原影象無變化!
cv::waitKey(0);
return 0;
}
//-----------------------------------OpenCV學習7-------------------------------------
// 程式名稱:在影象上左鍵點選響應為畫素位置灰度值、翻轉影象和在影象上繪圖
// 2016年10月 Created by孫立波(Visual Studio 2013+OpenCV2.4.9)
#include <opencv2\opencv.hpp>
#include <iostream>
#include <string>
using namespace cv;
using namespace std;
//回撥函式設定響應內容
void onMouse(int event, int x, int y, int flags, void* param)
{
cv::Mat *im = reinterpret_cast<cv::Mat*>(param);
switch (event)
{ // 排程事件列表及應響應的操作
case CV_EVENT_LBUTTONDOWN: // 滑鼠左鍵按下事件
// display pixel value at (x,y)
{
std::cout << "at (" << x << "," << y << ") value is: "
<< int(im->at<uchar>(cv::Point(x, y))) << std::endl;
break;
}
}
}
int main()
{
cv::Mat image; // 建立影象例項,看預設下建構函式分配的行列
std::cout << "This unread empty image is " << image.rows << " x "
<< image.cols << std::endl;
// read the input image as a gray-scale image
image = cv::imread("D:\\workplace\\opencv_training\\test1.png", CV_LOAD_IMAGE_GRAYSCALE);
if (image.empty())
{
std::cout << "Error reading image..." << std::endl;
return 0;
}
// 讀取影象的行列和通道顯示出來
std::cout << "This reading image is " << image.rows << " x "
<< image.cols << std::endl;
std::cout << "This image has "
<< image.channels() << " channel(s)" << std::endl;
cv::imshow("OriginalImage", image); // show the image
//利用滑鼠回撥函式的啟用函式,建立顯示影象的視窗和回撥函式的關聯,點選視窗內畫素點即顯示出來
cv::setMouseCallback("OriginalImage", onMouse, reinterpret_cast<void*>(&image));
cv::waitKey(0);
//翻轉影象
cv::Mat result; // we create another empty image
cv::flip(image, result, 1); // 水平翻轉原影象到結果影象
// 0 for vertical,
// negative for both
cv::namedWindow("FlipOutput Image"); // the output window
cv::imshow("FlipOutput Image", result);
cv::waitKey(0); // 0 to indefinitely wait for a key pressed
// specifying a positive value will wait for
// the given amount of msec
// 自建立一個空的影象視窗,裝載影象後可以畫圖和新增文字
cv::namedWindow("Drawing on an Image"); // define the window
cv::circle(image, // 源影象
cv::Point(155, 110), // 圓的中心座標,單位:畫素
65, // 半徑
0, // 線的顏色 (0代表黑色)
3); // 線粗
cv::putText(image, // 在已畫圓的影象上操作
"This is a dog.", // 所新增的text
cv::Point(40, 200), // 文字位置座標,單位:畫素
cv::FONT_HERSHEY_PLAIN, // 文字字型型別
2.0, // 字號
255, // 文字字型顏色 (here white)
2); // 文字厚度
cv::imshow("Drawing on an Image", image); // show the image
cv::waitKey(0); // 0 to indefinitely wait for a key pressed
return 0;
}
//-----------------------------------OpenCV學習8(i,j寫反了,導致程式執行不過去)-------------
// 程式名稱:在影象上加入椒鹽噪聲
// 2016年10月 Created by孫立波(Visual Studio 2013+OpenCV2.4.9)
#include <opencv2\opencv.hpp>
#include <iostream>
#include <string>
#include <stdlib.h> // for std::rand!!!這個很關鍵
using namespace cv;
using namespace std;
//椒鹽噪聲函式,採用for迴圈
void salt1(Mat image, int n) //n為椒鹽噪聲點的個數
{
int i, j;
for (int k = 0; k < n; k++)
{
i = rand() % image.cols;//!!!!!!!!!!!!!!!!當時把i,j寫反了,導致程式執行不過去。。。
j = rand() % image.rows;
if (image.type() == CV_8UC1)
{
image.at<uchar>(j, i) = 255;
}
else if (image.type() == CV_8UC3)
{
image.at<Vec3b>(j, i)[0] = 255;
image.at<Vec3b>(j, i)[1] = 255;
image.at<Vec3b>(j, i)[2] = 255;
}
}
}
// 下面的函式說明Mat_類的operator()方法比at()簡單
//This is an extra version of the function
// to illustrate the use of cv::Mat_
// works only for a 1-channel image
void salt2(cv::Mat image, int n)
{
// use image with a Mat_ template
cv::Mat_<uchar> im2(image);
// or with references:
// cv::Mat_<uchar>& im2= reinterpret_cast<cv::Mat_<uchar>&>(image);
int i, j;
for (int k = 0; k<n; k++)
{
// rand() is the MFC random number generator
i = rand() % image.cols;
j = rand() % image.rows;
if (im2.type() == CV_8UC1)
{
im2(j, i) = 255;// gray-level image
}
}
}
int main()
{
Mat image = imread("D:\\workplace\\opencv_training\\test3.jpg");
if (image.empty())
{
cout << "error:影象未裝載成功";
system("pause");//使控制檯介面保留
return -1; //除錯程式框會顯示返回值結果
}
imshow("Image", image);
waitKey();
salt1(image, 3000);
imshow("Salt_Image", image);
waitKey();
//重新將源影象的灰度影象格式裝入記憶體,測試對灰度影象加噪點的salt2函式
Mat image1 = imread("D:\\workplace\\opencv_training\\test3.jpg", 0);
salt2(image1, 3000);
imshow("Salt_Image2", image1);
waitKey();
return 0;
}
//-----------------------------------OpenCV學習9-------------------------------------
// 程式名稱:用函式和過載運算子加權兩個影象和將某影象一通道加權到一個影象再融合
// 2016年10月 Created by孫立波(Visual Studio 2013+OpenCV2.4.9)
#include <opencv2\opencv.hpp>
#include <iostream>
#include <string>
#include <vector>
using namespace cv;
using namespace std;
int main()
{
cv::Mat image1=imread("D:\\workplace\\opencv_training\\test3.jpg");
cv::Mat image2 =imread("D:\\workplace\\opencv_training\\test4.jpg");
if (!image1.data)
return 0;
if (!image2.data)
return 0;
cv::imshow("Image 1", image1);
cv::imshow("Image 2", image2);
cv::waitKey();
cv::Mat result;
// 加權兩個影象,顯示效果
cv::addWeighted(image1, 0.7, image2, 0.9, 0., result);
cv::imshow("result", result);
cv::waitKey();
// 使用過載運算子加權兩個影象
result = 0.7*image1 + 0.9*image2;
cv::imshow("result with operators", result);
image2 = cv::imread("D:\\workplace\\opencv_training\\test3.jpg", 0);
cv::waitKey();
//將某影象一通道加權到一個影象再融合
std::vector<cv::Mat> planes;// create vector of 3 images
// split 1個 3-channel image into 3個 1-channel images
cv::split(image1, planes);
// add to blue channel
planes[0] += image2;
// merge the 3 1-channel images into 1 3-channel image
cv::merge(planes, result);
cv::imshow("Result on blue channel", result);
cv::waitKey();
return 0;
}
//-----------------------------------OpenCV學習10-------------------------------------
// 程式名稱:測試幾個銳化函式,看哪個執行效率高且簡單
// 實驗證明:第三個採用了現成的濾波函式,但是模板核自己要做好的那個最好
// 2016年10月 Created by孫立波(Visual Studio 2013+OpenCV2.4.9)
#include <opencv2\opencv.hpp>
#include <iostream>
#include <string>
#include <vector>
using namespace cv;
using namespace std;
//銳化函式,該函式可以處理彩色影象
void sharpen(const cv::Mat &image, cv::Mat &result) {
result.create(image.size(), image.type()); // allocate if necessary
int nchannels = image.channels();
for (int j = 1; j<image.rows - 1; j++) { // for all rows (except first and last)
const uchar* previous = image.ptr<const uchar>(j - 1); // previous row
const uchar* current = image.ptr<const uchar>(j); // current row
const uchar* next = image.ptr<const uchar>(j + 1); // next row
uchar* output = result.ptr<uchar>(j); // output row
for (int i = nchannels; i<(image.cols - 1)*nchannels; i++) {
*output++ = cv::saturate_cast<uchar>(5 * current[i]
- current[i - nchannels] - current[i + nchannels] - previous[i] - next[i]);
//output[i]= cv::saturate_cast<uchar>
//(5*current[i]-current[i-nchannels]-current[i+nchannels]-previous[i]-next[i]);
}
}
// Set the unprocess pixels to 0
result.row(0).setTo(cv::Scalar(0));
result.row(result.rows - 1).setTo(cv::Scalar(0));
result.col(0).setTo(cv::Scalar(0));
result.col(result.cols - 1).setTo(cv::Scalar(0));
}
//同樣的銳化函式,但是使用了迭代器,該函式只能處理灰度影象
// this one works only for gray-level image
void sharpenIterator(const cv::Mat &image, cv::Mat &result) {
cv::Mat_<uchar>::const_iterator it = image.begin<uchar>() + image.cols;
cv::Mat_<uchar>::const_iterator itend = image.end<uchar>() - image.cols;
cv::Mat_<uchar>::const_iterator itup = image.begin<uchar>();
cv::Mat_<uchar>::const_iterator itdown = image.begin<uchar>() + 2 * image.cols;
result.create(image.size(), image.type()); // allocate if necessary
cv::Mat_<uchar>::iterator itout = result.begin<uchar>() + result.cols;
for (; it != itend; ++it, ++itout, ++itup, ++itdown) {
*itout = cv::saturate_cast<uchar>(*it * 5 - *(it - 1) - *(it + 1) - *itup - *itdown);
}
// Set the unprocess pixels to 0
result.row(0).setTo(cv::Scalar(0));
result.row(result.rows - 1).setTo(cv::Scalar(0));
result.col(0).setTo(cv::Scalar(0));
result.col(result.cols - 1).setTo(cv::Scalar(0));
}
//使用現成的濾波函式,但是模板核自己要做好
void sharpen2D(const cv::Mat &image, cv::Mat &result) {
// Construct kernel (all entries initialized to 0)
cv::Mat kernel(3, 3, CV_32F, cv::Scalar(0));
// assigns kernel values
kernel.at<float>(1, 1) = 5.0;
kernel.at<float>(0, 1) = -1.0;
kernel.at<float>(2, 1) = -1.0;
kernel.at<float>(1, 0) = -1.0;
kernel.at<float>(1, 2) = -1.0;
//filter the image
cv::filter2D(image, result, image.depth(), kernel);
}
int main()
{
cv::Mat image = cv::imread("D:\\workplace\\opencv_training\\test3.jpg");
if (!image.data)
return 0;
cv::Mat result;
//記錄第一個銳化函式時間,輸出效果
double time = static_cast<double>(cv::getTickCount());
sharpen(image, result);
time = (static_cast<double>(cv::getTickCount()) - time) / cv::getTickFrequency();
std::cout << "time= " << time << std::endl;
cv::imshow("Image", result);
//記錄第二個銳化函式時間,輸出效果
// open the image in gray-level
image = cv::imread("D:\\workplace\\opencv_training\\test3.jpg", 0);
time = static_cast<double>(cv::getTickCount());
sharpenIterator(image, result);
time = (static_cast<double>(cv::getTickCount()) - time) / cv::getTickFrequency();
std::cout << "time 3= " << time << std::endl;
cv::imshow("Sharpened Image", result);
//記錄第三個銳化函式時間,輸出效果
image = cv::imread("D:\\workplace\\opencv_training\\test3.jpg");
time = static_cast<double>(cv::getTickCount());
sharpen2D(image, result);
time = (static_cast<double>(cv::getTickCount()) - time) / cv::getTickFrequency();
std::cout << "time 2D= " << time << std::endl;
cv::imshow("Image 2D", result);
cv::waitKey();
return 0;
}
//-----------------------------------OpenCV學習11-------------------------------------
// 程式名稱:重對映函式remape舉例!!!只能應用於灰度影象
// 2016年10月 Created by孫立波(Visual Studio 2013+OpenCV2.4.9)
#include <opencv2\opencv.hpp>
#include <iostream>
#include <string>
#include <vector>
#include <math.h>
using namespace cv;
using namespace std;
// 使影象產生波動效果
void wave(const cv::Mat &image, cv::Mat &result) {
// the map functions
cv::Mat srcX(image.rows, image.cols, CV_32F); // x-map
cv::Mat srcY(image.rows, image.cols, CV_32F); // y-map
//對映引數畫素座標之間關係的建立,注:不是灰度值!
for (int i = 0; i<image.rows; i++) {
for (int j = 0; j<image.cols; j++) {
srcX.at<float>(i, j) = j;
srcY.at<float>(i, j) = i + 3 * sin(j / 6.0);
// horizontal flipping
// srcX.at<float>(i,j)= image.cols-j-1;
// srcY.at<float>(i,j)= i;
}
}
// // 應用對映函式!!!!!!!remape
cv::remap(image, // source image
result, // destination image
srcX, // x map
srcY, // y map
cv::INTER_LINEAR); // interpolation method
}
int main()
{
cv::Mat image = cv::imread("D:\\workplace\\opencv_training\\test3.jpg", 0);//0代表只能用其灰度影象
// image is resize for book printing
cv::resize(image, image, cv::Size(), 0.6, 0.6);//把影象變成原來的0.6倍
cv::imshow("Image", image);
cv::Mat result;
wave(image, result);
cv::imshow("Remapped image", result);
cv::waitKey();
return 0;
}
//-----------------------------------OpenCV學習12-------------------------------------
// 程式名稱:自定義類colordetector,分別用類成員函式RGB空間畫素檢測和仿函式實現Lab顏色空間畫素檢測
// 2016年10月 Created by孫立波(Visual Studio 2013+OpenCV2.4.9)
#include <opencv2\opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
#include "colordetector.h"//需要定義該類的標頭檔案(小段函式定義放在標頭檔案)和類外成員函式定義(較長的函式體)
int main()
{
// 1. Create image processor object
ColorDetector cdetect;
// 2. Read input image
cv::Mat image = cv::imread("D:\\workplace\\opencv_training\\test3.jpg");
if (image.empty())
return 0;
// 3. Set input parameters
cdetect.setTargetColor(230, 190, 130); // here blue sky
// 4. Process the image and display the result
cv::namedWindow("result");
cv::imshow("result", cdetect.process(image));
// or using functor使用函式物件或者仿函式
ColorDetector colordetector(230, 190, 130, // color
45, true); // Lab threshold,true代表使用Lab顏色空間
cv::namedWindow("result (functor)");
cv::imshow("result (functor)", colordetector(image));//物件呼叫了operator()運算子成員函式
cv::waitKey();
return 0;
}
//-----------------------------------OpenCV學習13-------------------------------------
// 程式名稱:自定義控制器類進行GUI和模型之間的通訊!!!,實現對使用者的封裝
// 2016年10月 Created by孫立波(Visual Studio 2013+OpenCV2.4.9)
#include <opencv2\opencv.hpp>
#include <iostream>
#include <stdio.h>
using namespace cv;
using namespace std;
#include "colorDetectController.h"//控制器類完成GUI和模型之間的通訊!!!
int main()
{
// Create the controller
ColorDetectController controller;
// To display the result
cv::namedWindow("Image");
// The following code simulate a user Interface
// based on the use of a controller
// Interaction with user is simply done
// using key pressed
std::cout << "q: to quit" << std::endl;
std::cout << "f: to input a filename" << std::endl;
std::cout << "t: to input target color values" << std::endl;
std::cout << "c: to input color distance threshold" << std::endl;
std::cout << "v: to view the different parameter values" << std::endl;
std::cout << "r: to run" << std::endl;
char key = ' ';
std::string filename;
while ((key = getchar()) != 'q') {
switch (key) {
uchar r, g, b;
case 'f': // read an image
std::cout << std::endl << "Filename? ";
std::cin >> filename;
std::cout << std::endl;
if (controller.setInputImage(filename))
std::cout << "...image successfully opened" << std::endl;
else
std::cout << "...cannot find image: " << filename << std::endl;
break;
case 't': // input target color
int ir, ig, ib;
std::cout << std::endl << "Target color? ";
std::cin >> ir >> ig >> ib;
std::cout << std::endl;
controller.setTargetColor(ir, ig, ib);
break;
case 'c': // input threshold
int th;
std::cout << std::endl << "Color distance threshold? ";
std::cin >> th;
std::cout << std::endl;
controller.setColorDistanceThreshold(th);
break;
case 'v': // view the parameters
std::cout << std::endl << "Image name: " << filename << std::endl;
controller.getTargetColour(r, g, b);
std::cout << std::endl << "Target color: "
<< static_cast<int>(r) << ","
<< static_cast<int>(g) << ","
<< static_cast<int>(b) << std::endl;
std::cout << std::endl << "Distance thresdhold: " << controller.getColorDistanceThreshold() << std::endl;
std::cout << std::endl;
break;
case 'i': // show input image
cv::imshow("Image", controller.getInputImage());
cv::waitKey(10); // for window to repaint
break;
case 'r': // run color detection
controller.process();
cv::imshow("Image", controller.getLastResult());
cv::waitKey(10); // for window to repaint
break;
}
}
return 0;
}
// ---------------------------------- - OpenCV學習14------------------------------------ -
// 程式名稱:顯示HSV個通道影象和利用色調和飽和度的數值區間做掩膜,實現人臉初步檢測
// 2016年10月 Created by孫立波(Visual Studio 2013+OpenCV2.4.9)
#include <opencv2\opencv.hpp>
#include <iostream>
#include <vector>
using namespace cv;
using namespace std;
void detectHScolor(const cv::Mat& image, // 輸入源影象
double minHue, double maxHue, // Hue interval
double minSat, double maxSat, // saturation interval
cv::Mat& mask) // 輸出掩碼
{
//將原影象先轉換到 HSV 顏色空間
cv::Mat hsv;
cv::cvtColor(image, hsv, CV_BGR2HSV);
// 分割3通道的hsv影象到3個獨立矩陣物件
std::vector<cv::Mat> channels;
cv::split(hsv, channels);
// channels[0] is the Hue
// channels[1] is the Saturation
// channels[2] is the Value
// 色調掩碼的構建
cv::Mat mask1; // under maxHue
cv::threshold(channels[0], mask1, maxHue, 255, cv::THRESH_BINARY_INV);
cv::Mat mask2; // over minHue
cv::threshold(channels[0], mask2, minHue, 255, cv::THRESH_BINARY);
cv::Mat hueMask; // hue mask
if (minHue < maxHue)
hueMask = mask1 & mask2;
else // if interval crosses the zero-degree axis
hueMask = mask1 | mask2;
// 飽和度掩碼構建
// under maxSat
cv::threshold(channels[1], mask1, maxSat, 255, cv::THRESH_BINARY_INV);
// over minSat
cv::threshold(channels[1], mask2, minSat, 255, cv::THRESH_BINARY);
cv::Mat satMask; // saturation mask
satMask = mask1 & mask2;
// 色調和飽和度掩碼的組合
mask = hueMask&satMask;
}
int main()
{
cv::Mat image = cv::imread("D:\\workplace\\opencv_training\\test3.jpg");
if (!image.data)
return 0;
cv::imshow("Original image", image);
//建立源影象的HSV顏色空間轉換
cv::Mat hsv;
cv::cvtColor(image, hsv, CV_BGR2HSV);
// 分割3通道的hsv影象到3個獨立矩陣物件
std::vector<cv::Mat> channels;
cv::split(hsv, channels);
// 顯示亮度值:即灰度值最高的那個灰度值
cv::imshow("Value", channels[2]);
// 顯示飽和度影象
cv::imshow("Saturation", channels[1]);
// 顯示色調影象
cv::imshow("Hue", channels[0]);
waitKey();
// image with fixed value固定亮度值通道值全為255
cv::Mat newImage;
cv::Mat tmp(channels[2].clone());
// Value channel will be 255 for all pixels
channels[2] = 255;
// merge back the channels
cv::merge(channels, hsv);
// re-convert to BGR
cv::cvtColor(hsv, newImage, CV_HSV2BGR);
cv::imshow("Fixed Value Image", newImage);
waitKey();
// image with fixed saturation固定飽和度值通道值全為255
channels[1] = 255;
channels[2] = tmp;
cv::merge(channels, hsv);
cv::cvtColor(hsv, newImage, CV_HSV2BGR);
cv::imshow("Fixed saturation", newImage);
waitKey();
// image with fixed value and fixed saturation固定亮度值和飽和度值通道值全為255
channels[1] = 255;
channels[2] = 255;
cv::merge(channels, hsv);
cv::cvtColor(hsv, newImage, CV_HSV2BGR);
cv::imshow("Fixed saturation/value", newImage);
waitKey();
// 進行人臉面板的初步檢測
image = cv::imread("D:\\workplace\\opencv_training\\test5.png");
if (!image.data)
return 0;
cv::imshow("Original image", image);
waitKey();
// detect skin tone檢測膚色
cv::Mat mask;
detectHScolor(image,
160, 10, //這個很重要: