OpenCV 基礎,常用方法 導入頭文件 #include <opencv2/opencv.hpp> #include <opencv2/highgui/highgui.hpp> #include <opencv2/imgproc/imgproc.hpp> using namespace cv; using namespace std; //讀取圖片 void fun_imread(Mat img) { Mat img1; imshow("原圖", img);//圖像顯示 waitKey();//讀入圖片顯示時間waitKey(6000);顯示6000毫秒,如果寫,就一直顯示 } //腐蝕操作函數 void fun_fs(Mat img) { //進行腐蝕操作 //卷積核所覆蓋下的原圖對應區域內的所有像素的最小值,用這個最小值替換當前像素值。圖片通過這種局部顏色加深, //導致整體顏色加深 Mat element = getStructuringElement(MORPH_RECT, Size(10, 10));// Size的參數是卷積核的大小,越大腐蝕越嚴重。 //Mat element = getStructuringElement(MORPH_RECT, Size(15, 15)); Mat dstImage; erode(img, dstImage, element); imshow("腐蝕操作后的圖", dstImage);//腐蝕操作的函數 waitKey(); } //膨脹 void fun_pz(Mat img) { //腐蝕和膨脹區別是函數imshow("膨脹操作后的圖", dstImage)//和池化操作類似 //卷積核所覆蓋下的原圖對應區域內的所有像素的最大,用這個最小值替換當前像素值。圖片通過這種局部顏色變淺, //導致整體顏色變淺 Mat element = getStructuringElement(MORPH_RECT, Size(10, 10));// Size的參數是卷積核的大小,越大腐蝕越嚴重。 //Mat element = getStructuringElement(MORPH_RECT, Size(15, 15)); //getStructuringElement獲取結構元素 Mat dstImage; dilate(img, dstImage, element);//第一個參數是輸入圖片,第二個參數是輸出圖片,第三個是 imshow("膨脹操作后的圖", dstImage); //膨脹操作的函數 waitKey(); } 均值濾波 void fun_mh(Mat img) { //圖片模糊的本質是對圖片進行均值濾波,就是均值池化類似的操作 Mat dstImage; blur(img, dstImage, Size(7, 7));//均值濾波 imshow("均值濾波【效果圖】", dstImage); waitKey(); } //中值濾波 中值濾波可以有效濾除椒鹽噪聲 medianBlur(img1, img2, 3); //也會變模糊,但程度相對較小 imshow("中值濾波后", img2); //均值濾波 均值濾波能夠濾除白噪聲,但會使原始圖像丟掉一些細節(原圖變得模糊) blur(img1, img2, Size(3,3)); imshow("均值濾波后", img2); //高斯濾波 一般圖像采取的都是高斯濾波 //加權均值濾波(高斯濾波)也可以有效的濾除白噪聲,同時不會丟掉原圖中的細節(甚至原圖更清晰) GaussianBlur(img1, img2, Size(3,3),5);//size的大小調節不好會報錯size越大越模糊 imshow("高斯濾波后", img2); //轉灰度圖,進行邊緣輪廓檢測 void fun_hd(Mat img) { //將圖片變成灰度圖 Mat dstImage,img1; blur(img, dstImage, Size(4, 4));//1、均值濾波 cvtColor(dstImage, dstImage, COLOR_BGR2GRAY);//2、轉成灰度圖 cout << dstImage.at<Vec3b>(2, 2)[1]; imshow("灰度圖", dstImage); Canny(dstImage, img1, 50, 120, 3); //3、使用邊緣檢測 //canny 第一個數字越大 imshow("邊緣檢測", img1); waitKey(0); } void fun(Mat img1) { Mat img; //創建相同大小相同類型的矩陣 img.create(img1.size(),img1.type()); img.create(img1.size(), CV_32FC3); img = img1.clone(); img.rows;//行 img.cols;//列 } void fun_readvido() { //如果有視屏,則讀取視屏,如果沒有視屏參數寫0,調用本地攝像頭 //VideoCapture cap("C:\\Users\\MH\\Desktop\\常用工具類\\壁紙\\1.avi"); VideoCapture cap(0); while(1) { Mat frame; cap >> frame; Mat dstImage, img1; imshow("讀取視屏", img1); waitKey(10); } } //隨機產生椒鹽噪聲 Mat fun_1(Mat img1, int k) { Mat img = img1.clone(); int i, j; for (int m = 0; m < k; m++) {//循環k次,隨機產生k個點 i = rand() % img.rows; //img.at<Vec3b>(i, j)[0] = 0; i代表行下標(高rows),j代表列下標寫反位置會報錯 j = rand() % img.cols;//產生隨機的下標點 img.at<Vec3b>(i, j)[0] = 0; img.at<Vec3b>(i, j)[1] = 0; img.at<Vec3b>(i, j)[2] = 0; } for (int m = 0; m <int(k / 2); m++) { i = rand() % img.rows; j = rand() % img.cols; img.at<Vec3b>(i, j)[0] = 255; img.at<Vec3b>(i, j)[1] = 255; img.at<Vec3b>(i, j)[2] = 255; } return img; } //log圖像增強 Mat fun_log(Mat img) { Mat img1; float C = 0.5; img1.create(img.size(), CV_32FC3); for (int i = 0; i < img.rows; i++) { for (int j = 0; j < img.cols; j++) { img1.at<Vec3f>(i, j)[0] = C * log(1+float(img.at<Vec3b>(i, j)[0])); img1.at<Vec3f>(i, j)[1] = C * log(1+float(img.at<Vec3b>(i, j)[1])); img1.at<Vec3f>(i, j)[2] = C * log(1+float(img.at<Vec3b>(i, j)[2])); } } //歸一化到0~255 normalize(img1, img1, 0, 255, CV_MINMAX); //轉換成8bit圖像顯示 convertScaleAbs(img1, img1); return img1; } //指數對圖片進行放暗 Mat fun_3(Mat img) { int c = 3; float b = 0.1; Mat img1; //img1 = img.clone(); img1.create(img.size(), CV_32FC3);//32位的圖像像素灰度值在(0-1)之間的顯示是正常顯示,也可以將其轉化成0-255,然后轉乘8bit的圖 for (int m = 0; m < img.rows; m++) { for (int j = 0; j < img.cols; j++) { img1.at<Vec3f>(m, j)[0] = float(img.at<Vec3b>(m, j)[0]) / 255 * float(img.at<Vec3b>(m, j)[0]) / 255; img1.at<Vec3f>(m, j)[1] = float(img.at<Vec3b>(m, j)[1]) / 255 * float(img.at<Vec3b>(m, j)[1]) / 255; img1.at<Vec3f>(m, j)[2] = float(img.at<Vec3b>(m, j)[2]) / 255 * float(img.at<Vec3b>(m, j)[2]) / 255; } } return img1; } //霍夫變換+圖像旋轉校正+背景填充 //二值化 Mat fun_two(Mat img) { float a = 110; for (int i = 0; i < img.rows; i++) { for (int j = 0; j < img.cols; j++) { if (0.3*img.at<Vec3b>(i, j)[0] + 0.6*img.at<Vec3b>(i, j)[1] + 0.1*img.at<Vec3b>(i, j)[2] > a) { img.at<Vec3b>(i, j)[0] = 255; img.at<Vec3b>(i, j)[1] = 255; img.at<Vec3b>(i, j)[2] = 255; } else { img.at<Vec3b>(i, j)[0] = 0; img.at<Vec3b>(i, j)[1] = 0; img.at<Vec3b>(i, j)[2] = 0; } } } return img; } //背景 Mat fun_bj(Mat img, float a, float b, float c) { for (int i = 0; i < img.rows; i++) { for (int j = 0; j < img.cols; j++) { if (0.3*img.at<Vec3b>(i, j)[0] + 0.6*img.at<Vec3b>(i, j)[1] + 0.1*img.at<Vec3b>(i, j)[2] == 255) { img.at<Vec3b>(i, j)[0] = a; img.at<Vec3b>(i, j)[1] = b; img.at<Vec3b>(i, j)[2] = c; } else { img.at<Vec3b>(i, j)[0] = 0; img.at<Vec3b>(i, j)[1] = 0; img.at<Vec3b>(i, j)[2] = 0; } } } return img; } //畫線的函數 void fun_line(vector<Vec2f> lines, Mat img) { for (size_t i = 0; i < lines.size(); i++) { float rho = lines[i][0]; float theta = lines[i][1]; double a = cos(theta), b = sin(theta); double x0 = a * rho, y0 = b * rho; Point pt1(cvRound(x0 + 1000 * (-b)), cvRound(y0 + 1000 * (a))); Point pt2(cvRound(x0 - 1000 * (-b)), cvRound(y0 - 1000 * (a))); line(img, pt1, pt2, Scalar(0, 0, 255), 3, 8); } imshow("線性圖", img); } //圖片旋轉//放射變換 Mat rotateImage(Mat img, double jd) { Mat img1; //旋轉中心為圖像中心 Point2f center; center.x = float(img.cols / 2.0); center.y = float(img.rows / 2.0); int length = 0; length = sqrt(img.cols*img.cols + img.rows*img.rows); //計算二維旋轉的仿射變換矩陣 Mat M = getRotationMatrix2D(center, jd, 1); warpAffine(img, img1, M, Size(length, length), 1, 0, Scalar(255, 255, 255));//仿射變換,背景色填充為白色 return img1; } int main() { Mat imroa, img3; float a, b, c;// imroa = imread("C:\\Users\\MH\\Desktop\\pInFileName.jpg"); a = imroa.at<Vec3b>(int(imroa.rows*0.9), int(imroa.rows*0.6))[0]; b = imroa.at<Vec3b>(int(imroa.rows*0.9), int(imroa.rows*0.6))[1]; c = imroa.at<Vec3b>(int(imroa.rows*0.9), int(imroa.rows*0.6))[2]; imshow("原圖", imroa); for (int i = 0; i < 10; i++) { medianBlur(imroa, imroa, 7);//第三個參數一般設為奇數 } blur(imroa, imroa, Size(5, 5)); img3 = imroa.clone(); cvtColor(imroa, imroa, COLOR_BGR2GRAY); Canny(imroa, imroa, 50, 200, 3); vector<Vec2f> lines; //霍夫變換,獲取直線對象 HoughLines(imroa, lines, 1, CV_PI / 180, 300, 0, 0); //// 輸入,線條對象,極徑的步長,角度的步長,閾值(閾值越大對直線要求越高,提取的直線數量越少) float sum = 0; for (size_t i = 0; i < lines.size(); i++) { sum += lines[i][1]; } float jd = sum / lines.size() / CV_PI * 180; cout << lines.size() << endl; cout << jd; //二值化 img3 = fun_two(img3); fun_line(lines,img3); Mat img2; //旋轉 img2 = rotateImage(img3, jd); //imshow("中值濾波后", imroa); //imroa = fun_two(imroa); //imshow("二值化", imroa); //背景顏色填充裁剪 Mat img4; fun_bj(img2, a, b, c); imshow("填充", img2); waitKey(); return 0; }
圖像處理的基本思路: