关于图像处理的OpenCV的编程案例(一)

  • Post author:
  • Post category:其他




第1章 图像处理系统



1.1 翻转

flip函数实现图像的翻转功能,其语法结构为:


flip(InputArray src, OutputArray dst, int flipCode)


src:要处理的原始图像。

dst:与原始图像同样大小、类型的目标图像。

flipCode:是旋转类型。

flipCode=0,沿x轴方向翻转。

flipCode为任意正数,沿y轴方向翻转。

flipCode为任意负数,x轴、y轴同时翻转。

实现代码如下:

#include <opencv2/opencv.hpp>
#include<opencv2/highgui.hpp>
using namespace std;
using namespace cv;//包含cv命名空间
int main()
{
    Mat src_img = imread("01.bmp");//imread()函数载入图像
    if (src_img.empty())
    {
        fprintf(stderr, "Can not load image\n");//如果读入图像失败,返回错误信息
        return -1;
    }
    //显示图像
    imshow("origin image and rotate operation", src_img);//imshow()函数显示图像
    Mat des_img;
    flip(src_img, des_img, 1);//1等正数代表水平方向旋转180度
    imshow(" after rotate operation", des_img);//imshow()函数显示图像
    waitKey();
    return 0;
}

处理结果:

上图为原始图像,下图为经过旋转操作后的图像



1.2 形态学处理

调用morphologyEx函数来实现形态学的相关操作。该函数的语法结构如下:


morphologyEx(InputArray src, OutputArray dst, int op, InputArray kernel, Point anchor=Point(-1,-1), intiterations=1, int borderType=BORDER_CONSTANT, const Scalar& borderValue=morphologyDefaultBorderValue() )

类型 说明
MORPH_ERODE 腐蚀
MORPH_DILATE 膨胀
MORPH_OPEN 开运算
MORPH_CLOSE 闭运算
MORPH_GRADIENT 形态学梯度



1.2.1 腐蚀

Mat element = getStructuringElement(MORPH_RECT, Size(3, 3));
morphologyEx(src_img, des_img, MORPH_ERODE, element);

在这里插入图片描述



1.2.2 膨胀

Mat element = getStructuringElement(MORPH_RECT, Size(3, 3));
morphologyEx(src_img, des_img, MORPH_DILATE, element);

在这里插入图片描述



1.3滤波处理



1.3.1 均值滤波

  blur(src_img, dst_img, Size(3, 3));

在这里插入图片描述



1.3.2 高斯滤波

#include <opencv2/opencv.hpp>
#include<opencv2/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
using namespace std;
using namespace cv;//包含cv命名空间
int main()
{
    Mat src_img = imread("01.bmp");//imread()函数载入图像
    double sigmaX = 0;
    double sigmaY = 0;
    if (src_img.empty())
    {
        fprintf(stderr, "Can not load image\n");//如果读入图像失败,返回错误信息
        return -1;
    }
    imshow("origin image", src_img);
    Mat dst_img;
    GaussianBlur(src_img, dst_img,Size(5,5),sigmaX,sigmaY);
    imshow(" after operation", dst_img);
    waitKey();
    return 0;
}

在这里插入图片描述



1.3.3 中值滤波

    medianBlur(src_img, dst_img, 3);

在这里插入图片描述

中值滤波可以去除椒盐噪声。



1.4 缩放



1.4.1 pyrUp函数

该函数实现图像金字塔操作的向上采样,即放大功能。

pyrUp(src_img, dst_img, Size(src_img.cols*2,src_img.rows*2));

在这里插入图片描述

在这里插入图片描述

使用该函数时,只能固定对图像进行2倍的长宽放大。



1.4.2 pyrDown函数

该函数实现图像金字塔操作的向下采样,即实现缩小功能。

pyrDown(src_img, dst_img, Size(src_img.cols/2,src_img.rows/2));

在这里插入图片描述

同样地,使用该函数时,只能固定对图像进行2倍的长宽缩小。



1.4.3 resize函数

resize(src_img, dst_img,Size(), 0.6, 0.6,INTER_LINEAR);

在这里插入图片描述



第2章 医学图像处理算法学习系统



2.1 增强



2.1.1 直方图均衡化

该函数只能实现单通道的直方图均衡化,因此在对多通道图像进行直方图均衡化时,要首先将其进行通道分离,逐个进行均衡化,最后再将各个通道的均衡结果进行合并,就可以得到最终的直方图均衡化结果。

    vector<Mat> channels;//定义存储的容器
    split(src_img, channels);
    Mat bluechannel = channels[0];//b通道的图像
    equalizeHist(bluechannel, bluechannel);//均衡化
    Mat greenchannel = channels[1];//g通道的图像
    equalizeHist(greenchannel, greenchannel);
    Mat redchannel = channels[2];//r通道的图像
    equalizeHist(redchannel, redchannel);
    merge(channels, dst_img);//合并通道
    imshow(" 均衡后的图像", dst_img);//imshow()函数显示图像

在这里插入图片描述



2.1.2 对比度亮度

对比度:

src_img.convertTo(dst_img, -1, 2);调整对比度,仅仅调整alpha的值,此实验alpha=2,beta=0

在这里插入图片描述

亮度:

    src_img.convertTo(dst_img, -1, 1, 80);此时,aplha=1,beta=80.

在这里插入图片描述



2.2 卷积

此算子模板为:

0 -1 0

-1 5 -1

0 -1 0

Mat kernel = (Mat_<float>(3, 3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);
filter2D(src_img, dst_img, src_img.depth(), kernel);

在这里插入图片描述



2.3 重映射

把一幅图像内的像素点放置到另外一幅图像内的指定位置,称为重映射。



2.3.1 x轴

  Mat map_x, map_y;
  dst_img.create(src_img.size(), src_img.type());
  map_x.create(src_img.size(), CV_32FC1);
  map_y.create(src_img.size(), CV_32FC1);
  for (int i = 0; i < src_img.rows; i++)
  {
     for (int j = 0; j < src_img.cols; j++)
     {
         map_x.at<float>(i, j) = src_img.cols - j;
         map_y.at<float>(i, j) = i;
     }
 }
remap(src_img, dst_img, map_x, map_y, INTER_LINEAR, BORDER_CONSTANT, Scalar(0, 0, 0));

在这里插入图片描述



2.3.2 缩小

#include <opencv2/opencv.hpp>
#include<opencv2/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
using namespace std;
using namespace cv;//包含cv命名空间
int main()
{
    Mat src_img = imread("cat1.jpg");//imread()函数载入图像
    if (src_img.empty())
    {
        fprintf(stderr, "Can not load image\n");//如果读入图像失败,返回错误信息
        return -1;
    }
    //显示图像
    imshow("原始图像", src_img);//imshow()函数显示图像
    Mat dst_img;
    Mat map_x, map_y;
    dst_img.create(src_img.size(), src_img.type());
    map_x.create(src_img.size(), CV_32FC1);
    map_y.create(src_img.size(), CV_32FC1);
    for (int i = 0; i < src_img.rows; i++)
    {
        for (int j = 0; j < src_img.cols; j++)
        {
            if (i > src_img.rows * 0.25 && i < src_img.rows * 0.75 && j > src_img.cols * 0.25 && j<src_img.cols * 0.75)
            {
                map_x.at<float>(i, j) = 2 * (j - src_img.cols * 0.25) + 0.5;
                map_y.at<float>(i, j) = 2 * (i - src_img.rows * 0.25) + 0.5;
            }
            else
            {
                map_x.at<float>(i,j) = 1;//随机选取
                map_y.at<float>(i,j) = 1;//随机选取
            }
        }
    }
    //调用remap
    remap(src_img, dst_img, map_x, map_y, INTER_LINEAR, BORDER_CONSTANT, Scalar(0, 0, 0));
    imshow(" 操作后图像", dst_img);//imshow()函数显示图像
    waitKey();
    return 0;
}

在这里插入图片描述



2.4 分割

阈值分割是图像分割过程中常用额一种方法,它利用图像中像素点像素值的大小差异,通过设置阈值的方式将图像中的像素点进行分类,从而达到图像分割的目的。



2.4.1 基本阈值分割

cvtColor(src_img, src_img_gray, COLOR_RGB2GRAY);
int threshold_value = 128;
int max_BINARY_value = 255;
int threshold_type = THRESH_BINARY;
threshold(src_img_gray, dst_img, threshold_value, max_BINARY_value, threshold_type);

threshold函数定义如下:

threshold(InputArray src,OutputArray dst,double thresh,double maxval,int type)

阈值分割的类型如下表所示:

在这里插入图片描述

当阈值分割的类型选择THRESH_BINARY时,分割的结果图如下所示:

在这里插入图片描述

当阈值分割的类型选择THRESH_BINARY_INV时,分割结果图如下:

在这里插入图片描述

当阈值分割的类型选择THRESH_TRUNC时,分割结果图如下:

在这里插入图片描述



2.4.2 自适应阈值分割

自适应阈值分割的函数为adaptiveThreshold()

adaptiveThreshold(InputArray src,OutputArray dst,double maxValue,int adaptiveMethod,int thresholdType,int blocksize,double C)

参数adaptiveMethod:自适应阈值分割方法,具体方法如下:

类型 定义
ADAPTIVE_THRESH_MEAN_C 阈值T(x,y)的值为以当前像素点为中心的bolcksize*blocksize领域内的平均值减去C的值
ADAPTIVE_THRESH_GAUSSIAN_C 阈值T(x,y)的值为以当前像素点为中心的bolcksize*blocksize领域内的加权和减去C的值
cvtColor(src_img, src_img_gray, COLOR_RGB2GRAY);
int maxValue = 255;
int adaptiveMethod = ADAPTIVE_THRESH_MEAN_C;
int thresholdType = THRESH_BINARY;
int blocksize = 7;
double C = 1;
adaptiveThreshold(src_img_gray, dst_img, maxValue, adaptiveMethod, thresholdType,blocksize,C);

当adaptiveMethod选择为ADAPTIVE_THRESH_MEAN_C时,结果图如下:

在这里插入图片描述

当adaptiveMethod选择为ADAPTIVE_THRESH_GAUSSIAN_C时结果图如下:

在这里插入图片描述



第三章 图像边缘检测学习系统

通过边缘检测算子找到图像的边缘,这些边缘通常实在图像在灰度、色彩、纹理等方面的不连续位置。



3.1 Sobel

Sobel边缘检测算子是一种离散的微分算子,该算子结合了高斯平滑和微分求导运算。

#include <opencv2/opencv.hpp>
#include<opencv2/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
using namespace std;
using namespace cv;//包含cv命名空间
int main()
{
    Mat src_img = imread("cat1.jpg");//imread()函数载入图像
    if (src_img.empty())
    {
        fprintf(stderr, "Can not load image\n");//如果读入图像失败,返回错误信息
        return -1;
    }
    //显示图像
    imshow("原始图像", src_img);//imshow()函数显示图像
    Mat dst_img;
    Sobel(dst_img, dst_img, src_img.depth(),0,1);
    imshow(" Sobel算子", dst_img);//imshow()函数显示图像
    waitKey();
    return 0;
}

在这里插入图片描述



3.2 Canny

Canny边缘检测算法可分为5个步骤:

1.应用高斯滤波去除图像噪声。

2.计算梯度值的强度信息。

3.应用非最大化抑制去除边缘检测散杂相应。该步骤就是边缘细化的过程。

4.应用双阈值确定潜在的边缘信息。

5.滞后跟踪边缘:通过抑制与强边缘无连接的弱边缘来检测实际的边缘。

    Mat dst_img;
    cvtColor(src_img, dst_img, COLOR_BGR2GRAY);
    Canny(dst_img, dst_img, 30, 100);
    imshow(" Canny算子", dst_img);

在这里插入图片描述



3.3 Laplacian

Laplacian算子是一种二阶导数算子,具有旋转不变性,可以满足不同走向的图像边缘锐化的要求。

 Laplacian(src_img, dst_img, src_img.depth(),ksize=5);

在这里插入图片描述

 Laplacian(src_img, dst_img, src_img.depth(),ksize=3);

在这里插入图片描述



3.4 Scharr

Scharr滤波器是对Sobel算子的改进。

   Scharr(src_img, dst_img, src_img.depth(), 0, 1);

在这里插入图片描述



第四章 数字图像加密学习系统



4.1 混沌系统

在这里插入图片描述

该系统对初始值极为敏感,初始值稍微不同,就会出现完全不同的结果。

1.生成黑白图像:

在这里插入图片描述

下图生成的是一个黑白混沌图像:

#include <opencv2/opencv.hpp>
#include<opencv2/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
using namespace std;
using namespace cv;//包含cv命名空间
int main()
{
    int M = 379;
    int N = 301;
    float chaotic[379 * 301];
    //混沌序列赋初值
    double t=0.98;
    int i;
    chaotic[0] = t;
    //生成混沌序列
    for (i = 1; i < M * N; i++)
        chaotic[i] = 1 - 2 * chaotic[i - 1] * chaotic[i - 1];
    //将混沌序列二值化,只有0和255两个值
    for (i = 0; i < M * N; i++)
        if (chaotic[i] > 0)
            chaotic[i] = 255;
        else
            chaotic[i] = 0;
    //建立一个混沌图像
    Mat chaoticImg(M, N, CV_8UC1);
    int flag = 0;
    for (int y = 0; y < M; y++)
    {
        uchar* chaoticImgR = chaoticImg.ptr<uchar>(y);
        for (int x = 0; x < N; x++)
        {
            chaoticImgR[x] = chaotic[flag];
            flag++;
        }
    }
    imshow("test1", chaoticImg);
    waitKey();
    return 0;
}

在这里插入图片描述

2.生成二值图像:

在这里插入图片描述

3.生成灰度图像:

在这里插入图片描述

mod(a,b)是取模函数,返回a除以b的余数。灰度图像GOI中像素点的值区间为0-255。

   //处理为256个灰度级
    for (i = 0; i < M * N; i++)
    {
        tmp = chaotic[i] * 1000000;
        chaotic[i]=tmp % 256;
    }
    //将上面混沌序列二值化部分替换成处理256个灰度级就可得到一个灰度混沌图像

在这里插入图片描述

4.生成彩色图像:

生成彩色图像时,首先分别生成R,G,B这三个颜色空间,然后将这3个色彩空间组合成彩色图像。

R色彩空间生成的方式为:

在这里插入图片描述

G色彩空间生成的方式为:

在这里插入图片描述

B色彩空间生成的方式为:

在这里插入图片描述

#include <opencv2/opencv.hpp>
#include<opencv2/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
using namespace std;
using namespace cv;//包含cv命名空间
int main()
{
    int M = 200;
    int N = 200;
    float chaotic[200 * 200 * 3];
    double t=0.98;
    int i;
    chaotic[0] = t;
    //给整个混沌序列赋值
    for (i = 1; i < M * N * 3; i++)
        chaotic[i] = 1 - 2 * chaotic[i - 1] * chaotic[i - 1];
    int tmp;
    //处理为256个灰度级
    for (i = 0; i < M * N * 3; i++)
    {
        tmp = chaotic[i] * 10000;
        chaotic[i]=tmp % 256;
    }
    //定义一个混沌图像
    Mat chaoticImg(M, N, CV_8UC3);
    int flag = 0;
    //将混沌序列的值赋给混沌图像
    for (int y = 0; y < M; y++)
    {
        uchar* chaoticImgR = chaoticImg.ptr<uchar>(y);
        for (int x = 0; x < N; x++)
        {
            chaoticImgR[3*x] = chaotic[flag];
            chaoticImgR[3 * x + 1] = chaotic[flag + M * N];
            chaoticImgR[3 * x + 2] = chaotic[flag + 2 * M * N];
            flag = flag + 1;
        }
    }
    Mat chaoticImgShow;
    chaoticImg.copyTo(chaoticImgShow);
    //色彩空间转换
    cvtColor(chaoticImg, chaoticImg, COLOR_BGR2RGB);
    imshow("test3", chaoticImgShow);
    waitKey();
    return 0;
}

在这里插入图片描述



4.2 异或加密

根据异或运算的规则,假设xor(a,b)=c,则可以得到xor(a,c)=b,xor(b,c)=a。

1.加密过程

原始图像O与选定的加密密钥图像K进行异或运算

#include <opencv2/opencv.hpp>
#include<opencv2/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
using namespace std;
using namespace cv;//包含cv命名空间
void creatChaoticImage(float init,InputArray src_img,OutputArray chaoticImg)
{
    int MM, NN;
    MM = src_img.rows();
    NN = src_img.cols(); 
    //定义一个数组,赋混沌初始值
    float chaotic[200* 200 * 3];
    //混沌系统赋初始值
    int i;
    chaotic[0] = init;
    //计算混沌序列的值
    for (i = 1; i < MM * NN * 3; i++)
        chaotic[i] = 1 - 2 * chaotic[i - 1] * chaotic[i - 1];
    int tmp;
    //处理为256个灰度级
    for (i = 0; i < MM * NN * 3; i++)
    {
        tmp = chaotic[i] * 10000;
        chaotic[i] = tmp % 256;
    }
    //定义一个混沌图像
    Mat chaoticImgT(MM, NN, CV_8UC3);
    int flag = 0;
    //将混沌序列的值赋给混沌图像
    for (int y = 0; y < MM; y++)
    {
        uchar* chaoticImgR = chaoticImgT.ptr<uchar>(y);
        for (int x = 0; x < NN; x++)
        {
            chaoticImgR[3 * x] = chaotic[flag];
            chaoticImgR[3 * x + 1] = chaotic[flag + MM * NN];
            chaoticImgR[3 * x + 2] = chaotic[flag + 2 * MM * NN];
            flag = flag + 1;
        }
    }
    chaoticImgT.copyTo(chaoticImg);
    return;
}
int main()
{
    //读入原始图像
    Mat src_img=imread("1.bmp");
    imshow("原始图像", src_img);
    Mat dst_img;
    double t=0.98;
    Mat chaoticImg;
    creatChaoticImage(t,src_img,chaoticImg);
    bitwise_xor(src_img, chaoticImg, dst_img);
    imshow("加密后的图像",dst_img);
    Mat m(src_img.size(), CV_8UC3);
    dst_img.copyTo(m);
    imwrite("1.0.bmp", m);
    waitKey();
    return 0;
}

在这里插入图片描述

在这里插入图片描述

2.解密过程

加密图像OS与密钥图像K进行按位异或运算,得到原图像O。

在这里插入图片描述

在这里插入图片描述



4.3 置乱加密

置乱加密是将原始图像信息的位置进行重新排列,让图像看起来杂乱无章,从而实现加密的效果。

1.置乱过程:

用混沌系统产生一个长度为n的数列CI,将该数列进行排序,从而得到一个升序数列CIS。通过计算数列CIS中的每个数据在数列CI中的下标,得到一个数列I。置乱时,将待置乱的数列W按照数列I进行置乱排序得到WO。

#include <opencv2/opencv.hpp>
#include<opencv2/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
using namespace std;
using namespace cv;//包含cv命名空间
int main()
{
    //读入原始图像
    Mat src_img = imread("1.bmp");
    imshow("原始图像", src_img);
    double t = 0.98;
    int i,j;
    int MM, NN;
    MM = src_img.rows;
    NN = src_img.cols;
    double *chaotic = new double[MM * NN * 3];
    double *chaoticSort = new double[MM * NN * 3];
    int* chaoticIndex = new int[MM * NN * 3];
    chaotic[0] = t;
    for (i = 1; i < MM * NN * 3; i++)
        chaotic[i] = 1 - 2 * chaotic[i - 1] * chaotic[i - 1];
    memcpy(chaoticSort, chaotic, MM * NN * 3 * sizeof(double));
    //对chaoticSort进行排序
    sort(chaoticSort, chaoticSort + MM * NN * 3);
    //生成索引序列,计算chaoticSort在chaotic内的位置信息
    for (i = 0; i < MM * NN * 3; i++)
    {
        for (j = 0; j < MM * NN * 3; j++)
            if (chaoticSort[i] == chaotic[j])
                chaoticIndex[i] = j;
    }
    int flag = 0;
    Mat dst_img;
    src_img.copyTo(dst_img);
    //对图像进行加密
    for (int i = 0; i < MM; i++)
    {
        uchar *r0 = dst_img.ptr<uchar>(i);
        for (int j = 0; j < NN * 3; j++)
        {
            uchar* p0 = src_img.ptr<uchar>(chaoticIndex[flag] / (NN * 3));
            r0[j] = p0[chaoticIndex[flag] % (NN * 3)];
            flag++;
        }
    }
    imshow("置乱加密后的图像",dst_img);
    Mat m(src_img.size(), CV_8UC3);
    dst_img.copyTo(m);
    imwrite("2.bmp", m);
    waitKey();
    return 0;
}

在这里插入图片描述

在这里插入图片描述

2.逆置乱过程:

将需要置乱的数列标记为WO*,应用数列I实现对WO*进行逆置乱。

由于混沌系统自身对初始值的敏感性、不可预知性等特点,保证了上述置乱过程、逆置乱过程的安全性和可靠性。

在这里插入图片描述

在这里插入图片描述



版权声明:本文为weixin_55652921原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。