OpenCV实现基本灰度变换

来源:互联网 发布:华为软件官网 编辑:程序博客网 时间:2024/06/07 01:32

OpenCV小白一枚,最近在看数字图像处理第二版,看课本的同时想加深一下理解,自己动手写一些代码实现一下课本中的效果。

看到第三章了,实现一些基本灰度变换的效果。不同灰度变换只是使用的公式不同而已,核心思想都是在空间域直接对每一个像素的灰度值进行判断处理,代码很简单。

//基本灰度变换#include<iostream>#include<cmath>#include<fstream>#include <opencv2/imgproc/imgproc.hpp>#include <opencv2/highgui/highgui.hpp>using namespace std;using namespace cv;#define CUTTING_MAINTAIN 1#define CUTTING_LOW 0//查看像素值void View(Mat src){    ofstream PView;    PView.open("PView.txt");    int num = 0;    for (int i = 0;i < src.rows;i++)    {        for (int j = 0;j < src.cols;j++)        {            if (num == 50)            {                num = 0;                PView << endl;            }            else            {                int a = src.at<uchar>(i, j);                PView << a << " ";                num++;            }        }    }    PView.close();}//图像反转void Reverse(Mat src,Mat intermediate){    for (int i = 0;i < src.rows;i++)    {        for (int j = 0;j < src.cols;j++)        {            intermediate.at<uchar>(i, j) = 255 - src.at<uchar>(i, j);        }    }}//对数变换void Log(Mat src, Mat intermediate,int c){    for (int i = 0;i < src.rows;i++)    {        for (int j = 0;j < src.cols;j++)        {            int b = c*log(1+src.at<uchar>(i, j));            int d = b % 256;            intermediate.at<uchar>(i, j) = d;        }    }}//幂次变换void Power(Mat src, Mat intermediate,float gamma){    for (int i = 0;i < src.rows;i++)    {        for (int j = 0;j < src.cols;j++)        {            float c = pow(255, 1 - gamma);            int b = c*pow(src.at<uchar>(i, j), gamma);            int d = b % 256;            intermediate.at<uchar>(i, j) = d;        }    }}//对比拉伸void Stretch(Mat src, Mat intermediate,float r1, float s1, float r2, float s2 ){    float k1, k2, k3, b1, b2, b3;    k1 = s1 / r1;    b1 = 0.0;    k2 = (s2 - s1) / (r2 - r1);    b2 = (s1*r2 - s2*r1) / (r2 - r1);    k3 = (255.0 - s2) / (255.0 - r2);    b3 = (255.0*s2-r2*255.0) / (255.0 - r2);    cout  << b3;    for (int i = 0;i < src.rows;i++)    {        for (int j = 0;j < src.cols;j++)        {            if (src.at<uchar>(i, j) >= 0.0 && src.at<uchar>(i, j) <= r1)            {                int a = k1*src.at<uchar>(i, j) + b1;                int b = a % 256;                intermediate.at<uchar>(i, j) = b;            }            if (src.at<uchar>(i, j) >= r1 && src.at<uchar>(i, j) <= r2)            {                int a = k2*src.at<uchar>(i, j) + b2;                int b = a % 256;                intermediate.at<uchar>(i, j) = b;            }            if (src.at<uchar>(i, j) >= r2 && src.at<uchar>(i, j) <= 255.0)            {                int a = k3*src.at<uchar>(i, j) + b3;                int b = a % 256;                intermediate.at<uchar>(i, j) = b;            }        }    }}//灰度切割void Cutting(Mat src, Mat intermediate, float r1,float r2,int type,int low,int high){    if (type == CUTTING_MAINTAIN)    {        for (int i = 0;i < src.rows;i++)        {            for (int j = 0;j < src.cols;j++)            {                if (src.at<uchar>(i, j) >= 0.0 && src.at<uchar>(i, j) <= r1)                {                    intermediate.at<uchar>(i, j) = src.at<uchar>(i, j);                }                if (src.at<uchar>(i, j) >= r1 && src.at<uchar>(i, j) <= r2)                {                    intermediate.at<uchar>(i, j) = high;                }                if (src.at<uchar>(i, j) >= r2 && src.at<uchar>(i, j) <= 255.0)                {                    intermediate.at<uchar>(i, j) = src.at<uchar>(i, j);                }            }        }    }    else    {        for (int i = 0;i < src.rows;i++)        {            for (int j = 0;j < src.cols;j++)            {                if (src.at<uchar>(i, j) >= 0.0 && src.at<uchar>(i, j) <= r1)                {                    intermediate.at<uchar>(i, j) = low;                }                if (src.at<uchar>(i, j) >= r1 && src.at<uchar>(i, j) <= r2)                {                    intermediate.at<uchar>(i, j) = high;                }                if (src.at<uchar>(i, j) >= r2 && src.at<uchar>(i, j) <= 255.0)                {                    intermediate.at<uchar>(i, j) = low;                }            }        }    }}int main(){    Mat src = cv::imread("Spectrum.tif", 0),temp;    Mat intermediate(src.rows, src.cols, CV_8UC1);    //cv::resize(src, temp, Size(src.cols*0.6, src.rows*0.6));    cv::imshow("Source", src);    //View(src);    Reverse(src, intermediate);    //Log(src, intermediate,45);    //Power(src, intermediate, 0.8);    //Stretch(src, intermediate,32.0,96.0,160.0,224.0);    //Cutting(src, intermediate, 50.0, 100.0,CUTTING_MAINTAIN,0,255);    //cv::resize(intermediate, intermediate, Size(intermediate.cols*0.6, intermediate.rows*0.6));    cv::imshow("intermediate", intermediate);    cv::imwrite("D:\\Computer Software\\Visual Studio 2015\\Projects\\ImageProcessing\\ImageProcessing\\检测结果Spectrum-Reverse.tif", intermediate);    cv::waitKey(0);    return 0;}

代码里处理的图片都是《数字图像处理》的源图像,第二版的好像不再出版了,只找到了第三版的源图像,不过差不太多的。

书上的源图像和课后问题图像可以到这个网站下载:
数字图像处理各版本源图像及课后问题图像

附部分检测结果的图片:
1.幂次变换用于增强对比度:
源图像:幂次变换(γ=0.4):
2.灰度切割:
源图像:

增强[50,100]区间灰度值为255,其余灰度值保持不变:

增强[50,100]区间灰度值为255,其余灰度值变化为0:

改进一下:
实现鼠标交互操作:使用鼠标圈出矩形框,只对矩形框内像素进行处理,可以更直观的观察某种算法对图像产生的变化。下面以对比拉伸为例:

#include<iostream>#include <opencv2/imgproc/imgproc.hpp>#include <opencv2/highgui/highgui.hpp>#include <opencv2/core/core.hpp>using namespace std;using namespace cv;Rect rect;bool rect_flag = false;//获取鼠标所选取的矩形void onMouse(int event,int x,int y,int flags,void*param){    if (event == CV_EVENT_LBUTTONDOWN)    {        rect.x = x;        rect.y = y;        rect_flag = false;    }    if (event == CV_EVENT_LBUTTONUP)    {        rect.width = x - rect.x;        rect.height = y - rect.y;        rect_flag = true;    }}//对比拉伸void Stretch(Mat src, Mat intermediate,float r1, float s1, float r2, float s2 ){    float k1, k2, k3, b1, b2, b3;    k1 = s1 / r1;    b1 = 0.0;    k2 = (s2 - s1) / (r2 - r1);    b2 = (s1*r2 - s2*r1) / (r2 - r1);    k3 = (255.0 - s2) / (255.0 - r2);    b3 = (255.0*s2-r2*255.0) / (255.0 - r2);    for (int i = rect.y;i < rect.y+rect.height;i++)    {        for (int j = rect.x;j < rect.x+rect.width;j++)        {            if (src.at<uchar>(i, j) >= 0.0 && src.at<uchar>(i, j) <= r1)            {                int a = k1*src.at<uchar>(i, j) + b1;                int b = a % 256;                intermediate.at<uchar>(i, j) = b;            }            if (src.at<uchar>(i, j) >= r1 && src.at<uchar>(i, j) <= r2)            {                int a = k2*src.at<uchar>(i, j) + b2;                int b = a % 256;                intermediate.at<uchar>(i, j) = b;            }            if (src.at<uchar>(i, j) >= r2 && src.at<uchar>(i, j) <= 255.0)            {                int a = k3*src.at<uchar>(i, j) + b3;                int b = a % 256;                intermediate.at<uchar>(i, j) = b;            }        }    }}int main(){    Mat src = cv::imread("Pollen.tif", 0),temp, intermediate;    cv::resize(src, temp, Size(src.cols*0.6, src.rows*0.6));    cv::imshow("Source", temp);    namedWindow("intermediate",1);    setMouseCallback("intermediate", onMouse, 0);       while (1)    {        cv::resize(src, intermediate, Size(src.cols*0.6, src.rows*0.6));        //消除第一次画矩形后第二次点击鼠标直接在点击位置画出与上一个矩形等大矩形的情况        if (rect_flag)        {            Stretch(temp, intermediate, 100.0, 1.0, 120.0, 254.0);            cv::rectangle(intermediate, rect, Scalar(255, 0, 0), 1);        }        cv::imshow("intermediate", intermediate);        //ESC按键        char c = (char)waitKey(20);        if (27 == c)            return -1;    }    return 0;}

效果图

0 0
原创粉丝点击