数字图像处理OpenCV——实验二 图像的空间域增强

简介: 实验二 图像的空间域增强实验项目名称:图像的空间域增强(1) 进一步理解图像平滑和图像锐化等空间域增强方法的原理。(2) 了解图像平滑和图像锐化的效果和作用。(3) 掌握图像模板运算的流程。1、图像平滑众所周知,实际获得的图像在形成、传输、接收和处理的过程中,不可避免地存在着外部和内部的噪声干扰。噪声恶化了图像质量,使图像模糊,给分析带来困难。因此,去除噪声,恢复原始图像时图像处理中的一个重要内容。消除图像噪声的工作称之为图像平滑或滤波。图像平滑方法包括空域法和频域法两大类。在空域法中,图像平

 实验二 图像的空间域增强

实验项目名称:图像的空间域增强

实验项目性质:设计性实验

所属课程名称:数字图像分析与艺术化处理

实验计划学时:2

一、实验目的

    1. 进一步理解图像平滑和图像锐化等空间域增强方法的原理。
    2. 了解图像平滑和图像锐化的效果和作用。
    3. 掌握图像模板运算的流程。

    二、实验主要仪器设备和材料

    计算机,VS+OpenCV

    三、实验原理

    1、图像平滑

    众所周知,实际获得的图像在形成、传输、接收和处理的过程中,不可避免地存在着外部和内部的噪声干扰。噪声恶化了图像质量,使图像模糊,给分析带来困难。因此,去除噪声,恢复原始图像时图像处理中的一个重要内容。消除图像噪声的工作称之为图像平滑或滤波。

    图像平滑方法包括空域法和频域法两大类。在空域法中,图像平滑常用的方法是采用均值滤波或中值滤波。对于均值滤波,它是采用一个有奇数点的滑动窗口在图像上滑动,将窗口中心点对应的图像像素点的灰度值用窗口内的各个点的灰度值的平均值代替,在取均值过程中,如果窗口规定了各个像素点所占的权重,也就是各个像素点的系数,则称为加权均值滤波。对于中值滤波,窗口中心点所对应像素的灰度值用窗口内所有像素的中间值代替。实现均值或中值滤波时,可以定义一个n*n的模板数组。另外,读者需要注意一点,在用窗口扫描图像过程中,对于图像四个边缘的像素点,可以不处理;也可以用灰度值为"0"的像素点扩展图像的边缘。

    2、图象锐化

    锐化处理的主要目的是突出图像中的细节或者增强被模糊了的细节,这种模糊不是由于错误操作,就是特殊图像获取方法的固有影响。图像均值滤波器可以使图像变模糊,是因为均值处理与积分相类似,因此可以对其进行逆运算(如微分运算)就可以使图像变得清晰。

    常常采用基于一阶或二阶微分的锐化滤波器实现图像的锐化处理。一阶微分是通过梯度法来实现的。对于图像f(i,j),它在点(i,j)处的梯度是一个矢量,定义为:

    image.gif编辑

    利用差分法近似上述公式,得到:

    image.gif编辑

    为了便于编程和提高运算,可进一步简化为:

    image.gif编辑

    利用差分运算时,图像的第一行和第一列的像素的梯度无法求得,一般用后一行或后一列的梯度值近似代替。微分运算可以增强图像高频分量(边缘等细节),但是仅仅微分处理后的图像非常暗,因此既要增强图像边缘,又要保持目标物体的内部灰度不变,常采用给边缘规定一个特定的灰度级的方法来完成梯度锐化处理。公式为:

    image.gif编辑

    La为一指定的灰度值,它将边界的灰度值统一化,这样可以使其边界更加清晰明显。该方法基本上不破坏图像的背景,又可找到边缘,并根据需要增强边缘。

    基于二阶微分的锐化滤波器,即拉普拉斯增强算子。一个二元图像函数f(x, y)的拉普拉斯变换定义为:

    image.gif编辑

    由于拉普拉斯是一种微分算子,它的应用强调图像中灰度的突变及降低灰度慢变化的区域,这将产生一幅把图像中的浅灰色边线和突变点叠加到暗背景中的图像。将原始图像和拉普拉斯图像叠加在一起的简单方法可以保护拉普拉斯锐化处理的效果,同时又能复原背景信息。这种方法可表示为:image.gif编辑

    四、实验内容和要求

    编程实现车牌图像的去噪和锐化处理。首先对图像去噪,分别采用均值滤波器和中值滤波器进行处理,比较两种滤波器效果;然后对去噪后的图像进行锐化,分别采用一阶微分和二阶微分,比较锐化效果。

    五、实验设计思路

    1.均值滤波器即把邻域内的平均值赋给中心元素。

    2.中值滤波器即把邻域内的中值赋给中心元素。

    3. 对去噪图像进行像素值进行一阶微分与二阶微分,得到锐化图像。

    六、实验代码

    #include <iostream>  
    #include <opencv2/opencv.hpp>  
    using namespace std;
    using namespace cv;
    //均值滤波函数
    void AverFiltering(const Mat& src, Mat& dst) {
      if (!src.data) return;
      //at访问像素点
      for (int i = 0; i < src.rows; ++i)
        for (int j = 0; j < src.cols; ++j) {
          if (i >= 1 && j >= 1 && i < src.rows - 1 && j < src.cols - 1) {//边缘不进行处理
            dst.at<Vec3b>(i, j)[0] = (src.at<Vec3b>(i, j)[0] + src.at<Vec3b>(i - 1, j - 1)[0] + src.at<Vec3b>(i - 1, j)[0] + src.at<Vec3b>(i, j - 1)[0] +
              src.at<Vec3b>(i - 1, j + 1)[0] + src.at<Vec3b>(i + 1, j - 1)[0] + src.at<Vec3b>(i + 1, j + 1)[0] + src.at<Vec3b>(i, j + 1)[0] +
              src.at<Vec3b>(i + 1, j)[0]) / 9;
            dst.at<Vec3b>(i, j)[1] = (src.at<Vec3b>(i, j)[1] + src.at<Vec3b>(i - 1, j - 1)[1] + src.at<Vec3b>(i - 1, j)[1] + src.at<Vec3b>(i, j - 1)[1] +
              src.at<Vec3b>(i - 1, j + 1)[1] + src.at<Vec3b>(i + 1, j - 1)[1] + src.at<Vec3b>(i + 1, j + 1)[1] + src.at<Vec3b>(i, j + 1)[1] +
              src.at<Vec3b>(i + 1, j)[1]) / 9;
            dst.at<Vec3b>(i, j)[2] = (src.at<Vec3b>(i, j)[2] + src.at<Vec3b>(i - 1, j - 1)[2] + src.at<Vec3b>(i - 1, j)[2] + src.at<Vec3b>(i, j - 1)[2] +
              src.at<Vec3b>(i - 1, j + 1)[2] + src.at<Vec3b>(i + 1, j - 1)[2] + src.at<Vec3b>(i + 1, j + 1)[2] + src.at<Vec3b>(i, j + 1)[2] +
              src.at<Vec3b>(i + 1, j)[2]) / 9;
          }
          else {//边缘赋值
            dst.at<Vec3b>(i, j)[0] = src.at<Vec3b>(i, j)[0];
            dst.at<Vec3b>(i, j)[1] = src.at<Vec3b>(i, j)[1];
            dst.at<Vec3b>(i, j)[2] = src.at<Vec3b>(i, j)[2];
          }
        }
    }
    //求九个数的中值
    uchar Median(uchar n1, uchar n2, uchar n3, uchar n4, uchar n5,
      uchar n6, uchar n7, uchar n8, uchar n9) {
      uchar arr[9];
      arr[0] = n1;
      arr[1] = n2;
      arr[2] = n3;
      arr[3] = n4;
      arr[4] = n5;
      arr[5] = n6;
      arr[6] = n7;
      arr[7] = n8;
      arr[8] = n9;
      sort(arr, arr + 9);//指针
      //for (int gap = 9 / 2; gap > 0; gap /= 2)//希尔排序
      //  for (int i = gap; i < 9; ++i)
      //    for (int j = i - gap; j >= 0 && arr[j] > arr[j + gap]; j -= gap)
      //      swap(arr[j], arr[j + gap]);
      return arr[4];//返回中值
    }
    //中值滤波函数
    void MedianFlitering(const Mat& src, Mat& dst) {
      if (!src.data)return;
      for (int i = 0; i < src.rows; ++i)
        for (int j = 0; j < src.cols; ++j) {
          if (i > 1 && i < src.rows - 1 && j > 1 && j < src.cols - 1) {
            dst.at<Vec3b>(i, j)[0] = Median(src.at<Vec3b>(i, j)[0], src.at<Vec3b>(i + 1, j + 1)[0],
              src.at<Vec3b>(i + 1, j)[0], src.at<Vec3b>(i, j + 1)[0], src.at<Vec3b>(i + 1, j - 1)[0],
              src.at<Vec3b>(i - 1, j + 1)[0], src.at<Vec3b>(i - 1, j)[0], src.at<Vec3b>(i, j - 1)[0],
              src.at<Vec3b>(i - 1, j - 1)[0]);
            dst.at<Vec3b>(i, j)[1] = Median(src.at<Vec3b>(i, j)[1], src.at<Vec3b>(i + 1, j + 1)[1],
              src.at<Vec3b>(i + 1, j)[1], src.at<Vec3b>(i, j + 1)[1], src.at<Vec3b>(i + 1, j - 1)[1],
              src.at<Vec3b>(i - 1, j + 1)[1], src.at<Vec3b>(i - 1, j)[1], src.at<Vec3b>(i, j - 1)[1],
              src.at<Vec3b>(i - 1, j - 1)[1]);
            dst.at<Vec3b>(i, j)[2] = Median(src.at<Vec3b>(i, j)[2], src.at<Vec3b>(i + 1, j + 1)[2],
              src.at<Vec3b>(i + 1, j)[2], src.at<Vec3b>(i, j + 1)[2], src.at<Vec3b>(i + 1, j - 1)[2],
              src.at<Vec3b>(i - 1, j + 1)[2], src.at<Vec3b>(i - 1, j)[2], src.at<Vec3b>(i, j - 1)[2],
              src.at<Vec3b>(i - 1, j - 1)[2]);
          }
          else {//边缘赋值
            dst.at<Vec3b>(i, j)[0] = src.at<Vec3b>(i, j)[0];
            dst.at<Vec3b>(i, j)[1] = src.at<Vec3b>(i, j)[1];
            dst.at<Vec3b>(i, j)[2] = src.at<Vec3b>(i, j)[2];
          }
        }
    }
    // 梯度锐化函数
    void DegreeSharpDeal(const Mat& src, Mat& dst) {
      if (!src.data)return;
      for (int i = 0; i < src.rows; ++i)
        for (int j = 0; j < src.cols; ++j) {
          float a, b, c;
          if (i > 1 && j > 1) {
            a = abs((float)src.at<Vec3b>(i, j)[0] - (float)src.at<Vec3b>(i - 1, j)[0]) + abs((float)src.at<Vec3b>(i, j)[0] - (float)src.at<Vec3b>(i, j - 1)[0]);
            b = abs((float)src.at<Vec3b>(i, j)[1] - (float)src.at<Vec3b>(i - 1, j)[1]) + abs((float)src.at<Vec3b>(i, j)[1] - (float)src.at<Vec3b>(i, j - 1)[1]);
            c = abs((float)src.at<Vec3b>(i, j)[2] - (float)src.at<Vec3b>(i - 1, j)[2]) + abs((float)src.at<Vec3b>(i, j)[2] - (float)src.at<Vec3b>(i, j - 1)[2]);
            a = a + src.at<Vec3b>(i, j)[0];
            b = b + src.at<Vec3b>(i, j)[1];
            c = c + src.at<Vec3b>(i, j)[2];
          }
          else {//边缘赋值
            a = src.at<Vec3b>(i, j)[0];
            b = src.at<Vec3b>(i, j)[1];
            c = src.at<Vec3b>(i, j)[2];
          }
          if (a > 255 || b > 255 || b > 255 || a < 0 || b < 0 || c < 0) {
            dst.at<Vec3b>(i, j)[0] = src.at<Vec3b>(i, j)[0];
            dst.at<Vec3b>(i, j)[1] = src.at<Vec3b>(i, j)[1];
            dst.at<Vec3b>(i, j)[2] = src.at<Vec3b>(i, j)[2];
          }
          else {
            dst.at<Vec3b>(i, j)[0] = a;
            dst.at<Vec3b>(i, j)[1] = b;
            dst.at<Vec3b>(i, j)[2] = c;
          }
        }
    }
    // 拉普拉斯锐化函数
    void LaplacianSharpDeal(const Mat& src, Mat& dst) {
      if (!src.data)return;
      Mat img(src.size(), src.type());
      for (int i = 0; i < src.rows; ++i)
        for (int j = 0; j < src.cols; ++j) {
          float a, b, c;
          if (i > 1 && i < src.rows - 1 && j > 1 && j < src.cols - 1) {
            a = 5 * (float)src.at<Vec3b>(i, j)[0] - (float)src.at<Vec3b>(i - 1, j)[0] - (float)src.at<Vec3b>(i, j - 1)[0] -
              (float)src.at<Vec3b>(i, j + 1)[0] - (float)src.at<Vec3b>(i + 1, j)[0];
            b = 5 * (float)src.at<Vec3b>(i, j)[1] - (float)src.at<Vec3b>(i - 1, j)[1] - (float)src.at<Vec3b>(i, j - 1)[1] -
              (float)src.at<Vec3b>(i, j + 1)[1] - (float)src.at<Vec3b>(i + 1, j)[1];
            c = 5 * (float)src.at<Vec3b>(i, j)[2] - (float)src.at<Vec3b>(i - 1, j)[2] - (float)src.at<Vec3b>(i, j - 1)[2] -
              (float)src.at<Vec3b>(i, j + 1)[2] - (float)src.at<Vec3b>(i + 1, j)[2];
          }
          else {//边缘赋值
            a = src.at<Vec3b>(i, j)[0];
            b = src.at<Vec3b>(i, j)[1];
            c = src.at<Vec3b>(i, j)[2];
          }
          if (a > 255 || b > 255 || b > 255 || a < 0 || b < 0 || c < 0) {
            dst.at<Vec3b>(i, j)[0] = src.at<Vec3b>(i, j)[0];
            dst.at<Vec3b>(i, j)[1] = src.at<Vec3b>(i, j)[1];
            dst.at<Vec3b>(i, j)[2] = src.at<Vec3b>(i, j)[2];
          }
          else {
            dst.at<Vec3b>(i, j)[0] = a;
            dst.at<Vec3b>(i, j)[1] = b;
            dst.at<Vec3b>(i, j)[2] = c;
          }
        }
    }
    void main() {
      Mat image = imread("噪声图像.bmp");
      Mat image1(image.size(), image.type());
      Mat image2(image.size(), image.type());
      Mat image3(image2.size(), image2.type());
      Mat image4(image2.size(), image2.type());
      AverFiltering(image, image1);
      MedianFlitering(image, image2);
      LaplacianSharpDeal(image2, image3);
      DegreeSharpDeal(image2, image4);
      imshow("原图像", image);
      imshow("均值滤波", image1);
      imshow("中值滤波", image2);
      imshow("拉普拉斯锐化处理", image3);
      imshow("梯度锐化处理", image4);
      waitKey();
    }

    image.gif

    七、实验结果与心得体会

    image.gif编辑

    实验结果明显,在此图像中使用中值滤波器与二阶微分效果更好。本次实验,更好的巩固了对图像去噪以及锐化的原理,使得不在仅限于原理的理解,而是从实践中更好的学习。通过此次实验,对今后图像处理的学习有了较大的帮助。

    相关文章
    |
    1月前
    |
    计算机视觉
    Opencv学习笔记(三):图像二值化函数cv2.threshold函数详解
    这篇文章详细介绍了OpenCV库中的图像二值化函数`cv2.threshold`,包括二值化的概念、常见的阈值类型、函数的参数说明以及通过代码实例展示了如何应用该函数进行图像二值化处理,并展示了运行结果。
    322 0
    Opencv学习笔记(三):图像二值化函数cv2.threshold函数详解
    |
    2月前
    |
    算法 计算机视觉
    opencv图像形态学
    图像形态学是一种基于数学形态学的图像处理技术,它主要用于分析和修改图像的形状和结构。
    49 4
    |
    2月前
    |
    存储 计算机视觉
    Opencv的基本操作(一)图像的读取显示存储及几何图形的绘制
    本文介绍了使用OpenCV进行图像读取、显示和存储的基本操作,以及如何绘制直线、圆形、矩形和文本等几何图形的方法。
    Opencv的基本操作(一)图像的读取显示存储及几何图形的绘制
    |
    3月前
    |
    算法 计算机视觉 Python
    python利用opencv进行相机标定获取参数,并根据畸变参数修正图像附有全部代码(流畅无痛版)
    该文章详细介绍了使用Python和OpenCV进行相机标定以获取畸变参数,并提供了修正图像畸变的全部代码,包括生成棋盘图、拍摄标定图像、标定过程和畸变矫正等步骤。
    python利用opencv进行相机标定获取参数,并根据畸变参数修正图像附有全部代码(流畅无痛版)
    WK
    |
    3月前
    |
    编解码 计算机视觉 Python
    如何在OpenCV中进行图像转换
    在OpenCV中,图像转换涉及颜色空间变换、大小调整及类型转换等操作。常用函数如`cvtColor`可实现BGR到RGB、灰度图或HSV的转换;`resize`则用于调整图像分辨率。此外,通过`astype`或`convertScaleAbs`可改变图像数据类型。对于复杂的几何变换,如仿射或透视变换,则可利用`warpAffine`和`warpPerspective`函数实现。这些技术为图像处理提供了强大的工具。
    WK
    108 1
    |
    5月前
    |
    算法 计算机视觉
    【Qt&OpenCV 图像的感兴趣区域ROI】
    【Qt&OpenCV 图像的感兴趣区域ROI】
    165 1
    |
    4月前
    |
    机器学习/深度学习 XML 计算机视觉
    OpenCV(Open Source Computer Vision Library)是一个开源的计算机视觉和机器学习库,它提供了大量的函数和工具,用于处理图像和视频数据。
    OpenCV(Open Source Computer Vision Library)是一个开源的计算机视觉和机器学习库,它提供了大量的函数和工具,用于处理图像和视频数据。
    |
    5月前
    |
    运维 算法 计算机视觉
    【Qt&OpenCV 图像的模板匹配 matchTemplate/minMaxLoc】
    【Qt&OpenCV 图像的模板匹配 matchTemplate/minMaxLoc】
    77 1
    |
    5月前
    |
    存储 编解码 算法
    【Qt&OpenCV 检测图像中的线/圆/轮廓 HoughLinesP/HoughCircles/findContours&drawContours】
    【Qt&OpenCV 检测图像中的线/圆/轮廓 HoughLinesP/HoughCircles/findContours&drawContours】
    89 0
    |
    5月前
    |
    计算机视觉
    OpenCV中图像算术操作与逻辑操作
    OpenCV中图像算术操作与逻辑操作
    66 1