圖像處理方法(膨脹腐蝕,霍夫變換,濾波,去噪,圖像增強,二值化,圖片旋轉,畫直線)


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;
}

 
圖像處理的基本思路:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM