一、实验目的

掌握 Opencv 进行图像处理的基础,实现图像的灰度变换处理。
1、掌握 OpenCV 的安装
2、掌握 OpenCV 对图像进行基本操作
3、掌握利用 OpenCV 对图像进行灰度变换

二、实验内容

1、利用 OpenCV 读取图像
具体内容:用打开 OpenCV 打开图像,并在窗口中显示
2、灰度图像二值化处理
具体内容:设置并调整阈值对图像进行二值化处理。
3、灰度图像的对数变换
具体内容:设置并调整 r 值对图像进行对数变换。
4、灰度图像的伽马变换
具体内容:设置并调整γ值对图像进行伽马变换。
5、彩色图像的补色变换
具体内容:对彩色图像进行补色变换。

三、实验完成情况

1、利用 OpenCV 读取图像

核心代码

//统一图片打开函数,用于简化路径和处理打开图片错误
Mat openImage(string name,int type = 1) {
    //图片读取函数,返回图像存储类(包含存储方式、存储矩阵、矩阵大小等)
    Mat img = imread(getFullPath(name),type);
    if (img.empty()) {
        cout << "无效图片,读取失败" << endl;
        exit(-1);
    }
    return img;
}
//打开图片显示窗口
void openWindows(string win_name, Mat img, int x = 500, int y = 500, bool close_window = true) {
    //窗口命名,指定大小,生成位置
    namedWindow(win_name, WINDOW_AUTOSIZE);
    moveWindow(win_name, x, y);
    //生成窗口显示图片
    imshow(win_name, img);
    //等待键入
    waitKey();
    //关闭窗口
    destroyWindow(win_name);
}

实现截图

python opencv 图像灰度平均值 opencv灰度变换_二值化

2.灰度图像二值化处理

核心代码

//灰度二值化处理,灰度阀值输入获取,最大值默认255
Mat handleBinary(int gray, int max = 255) {
    Mat result;
    //灰度处理,方式为二值化(THRESH_BINARY)
    threshold(img, result, gray, max, THRESH_BINARY);
    return result;
}

实现截图

python opencv 图像灰度平均值 opencv灰度变换_二值化_02

python opencv 图像灰度平均值 opencv灰度变换_二值化_03

3、灰度图像的对数变换

核心代码

//灰度对数变换,c值默认1
Mat handleLogarithmic(int c = 1) {
    //复制图像
    Mat src = img.clone();
    //图像元素变换为32F浮点类型
    src.convertTo(src, CV_32F);
    //建立空白目标图像结构
    Mat target = Mat::zeros(img.size(), img.type());
    //1+r   原图像与标量相加,由于是灰度图像,因此标量为Scalar(1.0),等同于src = src+1
    add(src, Scalar(1.0), src);
    //log(1+r) 对数变换
    log(src, target);
    //clog(1+r)
    target *= c;
    //归一化处理,即将变换后的图像平移、缩放到指定区间(0,255),归一化方式为最小值和最大值范围(NORM_MINMAX)
    normalize(target, target, 0, 255, NORM_MINMAX);
    //图像增强取绝对值并变换为U8整数类型,此处等同于target.convertTo(target, CV_8U);
    convertScaleAbs(target, target);
    return target;
}

实现截图

python opencv 图像灰度平均值 opencv灰度变换_灰度_04

4、灰度图像的伽马变换

核心代码

//灰度伽马变换,gamma值默认1
Mat handleGamma(double gamma = 1.0) {
    //复制图像
    Mat target = img.clone();
    //图像元素变换为64F浮点类型,并缩放到0~1区间内方便进行伽马变换
    target.convertTo(target, CV_64F, 1.0 / 255.0);
    //伽马变换
    pow(target, gamma, target);
    //图像元素缩放回0-255区间并变换为8U整数类型
    target.convertTo(target, CV_8U, 255.0);
    return target;
}

实现截图

python opencv 图像灰度平均值 opencv灰度变换_二值化_05

5、彩色图像的补色变换

核心代码

//反色变换,采用255-RGB方式,非补色
//Mat handleComplementary() {
//    Mat target = img.clone();
//    target = Scalar(255,255,255,255) - target;  //Scalar::all(255)
//    return target;
//}
//补色变换,采用255-RGB方式
Mat handleComplementary() {
    Mat target = img.clone();
    //将RGB转换为HSV
    cvtColor(target, target, COLOR_BGR2HSV);
    // target = Scalar(255,255,255,255) - target;  //Scalar::all(255)   RGB反色
    vector<Mat> mats;
    //分离图层
    split(target, mats);
    //色彩层补色处理
    mats[0] = Scalar::all(180) - mats[0];
    //将处理过的色彩层合并到图像中
    merge(mats, target);
    return target;
}

实现截图

python opencv 图像灰度平均值 opencv灰度变换_二值化_06

四、实验中的问题

  1. 已安装的VS2019组建损坏,无法完成正常的C++编译,因此重新安装了VS2019
  2. 实验指导中给定版本较旧,因此采用最新版本的OpenCV-4.5.2+VS2019进行实验,有很多地方与实验指导不一致,根据网上的教程进行环境配置。
  3. 重新熟悉C++耗费了一定时间和精力。

五、实验结果

源码

lab1.cpp

#include <opencv2/opencv.hpp>
#include <iostream>
#include <string>
#include "configs.h"

using namespace std;
using namespace cv;

const static std::string path = "F:\\Documents\\高级图像处理\\Image\\";

//图片路径组合
string getFullPath(string name) {
    return path + name;
}

//打开图片显示窗口
void openWindows(string win_name, Mat img, int x = 500, int y = 500, bool close_window = true) {
    //窗口命名,指定大小,生成位置
    namedWindow(win_name, WINDOW_AUTOSIZE);
    moveWindow(win_name, x, y);
    //生成窗口显示图片
    imshow(win_name, img);
    //等待键入
    waitKey();
    //关闭窗口
    destroyWindow(win_name);
}

//统一数字输入函数
template<typename T>T inputNumber(string desc) {
    system("cls");
    T input;
    cout << desc;
    cin >> input;
    cout << endl;
    return input;
}

//统一图片打开函数,用于简化路径和处理打开图片错误
Mat openImage(string name,int type = 1) {
    //图片读取函数,返回图像存储类(包含存储方式、存储矩阵、矩阵大小等)
    Mat img = imread(getFullPath(name),type);
    if (img.empty()) {
        cout << "无效图片,读取失败" << endl;
        exit(-1);
    }
    return img;
}

//彩色图像处理类
class ColorImage {

private:

    Mat img;

    //补色变换,采用255-RGB方式
    Mat handleComplementary() {
        Mat target = img.clone();
        //将RGB转换为HSV
        cvtColor(target, target, COLOR_BGR2HSV);
        // target = Scalar(255,255,255,255) - target;  //Scalar::all(255)   RGB反色
        vector<Mat> mats;
        //分离图层
        split(target, mats);
        //色彩层补色处理
        mats[0] = Scalar::all(180) - mats[0];
        //将处理过的色彩层合并到图像中
        merge(mats, target);
        return target;
    }

public:

    //读取彩色图像并展示
    ColorImage(string path) {
        img = openImage(path, IMREAD_COLOR);
        openWindows("彩色图像", img, false);
    }
    //补色变换接口
    void complementaryColorTransform() {
        openWindows("彩色补色图像", handleComplementary());
    }
};

//灰度图像处理类
class GrayImage {

private:

    Mat img;
  
    //灰度二值化处理,灰度阀值输入获取,最大值默认255
    Mat handleBinary(int gray, int max = 255) {
        Mat result;
        //灰度处理,方式为二值化(THRESH_BINARY)
        threshold(img, result, gray, max, THRESH_BINARY);
        return result;
    }

    //灰度对数变换,c值默认1
    Mat handleLogarithmic(int c = 1) {
        //复制图像
        Mat src = img.clone();
        //图像元素变换为32F浮点类型
        src.convertTo(src, CV_32F);
        //建立空白目标图像结构
        Mat target = Mat::zeros(img.size(), img.type());
        //1+r   原图像与标量相加,由于是灰度图像,因此标量为Scalar(1.0),等同于src = src+1
        add(src, Scalar(1.0), src);
        //log(1+r) 对数变换
        log(src, target);
        //clog(1+r)
        target *= c;
        //归一化处理,即将变换后的图像平移、缩放到指定区间(0,255),归一化方式为最小值和最大值范围(NORM_MINMAX)
        normalize(target, target, 0, 255, NORM_MINMAX);
        //图像增强取绝对值并变换为U8整数类型,此处等同于target.convertTo(target, CV_8U);
        convertScaleAbs(target, target);
        return target;
    }

    //灰度伽马变换,gamma值默认1
    Mat handleGamma(double gamma = 1.0) {
        //复制图像
        Mat target = img.clone();
        //图像元素变换为64F浮点类型,并缩放到0~1区间内方便进行伽马变换
        target.convertTo(target, CV_64F, 1.0 / 255.0);
        //伽马变换
        pow(target, gamma, target);
        //图像元素缩放回0-255区间并变换为8U整数类型
        target.convertTo(target, CV_8U, 255.0);
        return target;
    }

public:

    //仅读取灰度方式读取图像并展示(IMREAD_GRAYSCALE)
    GrayImage(string path) {
        img = openImage(path, IMREAD_GRAYSCALE);
        openWindows("灰度图像", img, false);
    }

    //灰度二值化接口,灰度阀值从输入获取
    void binaryProcessing() {
        int gray = inputNumber<int>("输入灰度阀值:");
        openWindows("灰度二值化", handleBinary(gray));
    }

    //灰度对数变换接口,c值取默认1
    void logarithmicTransform() {
        openWindows("灰度对数变换", handleLogarithmic());
    }

    //灰度伽马变换接口,伽马值从输入获取
    void gammaTransform() {
        double gamma = inputNumber<double>("输入伽马值:");
        openWindows("灰度伽马变换", handleGamma(gamma));
    }
};

int main(){
    
    //测试彩色图片1
    string name = "test.jpg";
    //彩色图片处理类
    ColorImage color_img(name);
    //补色变换
    color_img.complementaryColorTransform();
    
    //测试灰度图片
    name = "night.jpg";
    //灰度图片处理类
    GrayImage gray_img(name);
    //灰度二值化
    gray_img.binaryProcessing();
    //对数变换
    gray_img.logarithmicTransform();
    //伽马变换
    gray_img.gammaTransform();

    return 0;
}