• OpenCV学习(5)--离散傅里叶变换、滤波、侵蚀、扩张


    离散傅里叶变换

     1 // 离散傅里叶变换
     2 /*
     3 离散傅里叶变换(DFT),是傅里叶变换在时域和频域上都呈现离散的形式,将时域信号
     4 的采样变换为在离散时间傅里叶变换(DTFT)频域的采样。在形式上,变换两端(时域和
     5 频域上)的序列是有限长的,而实际上这两组序列都应当被认为是离散周期信号的主值序
     6 列。即使对有限长的离散信号作DFT,也应当将其看作经过周期延拓成为周期信号再作变
     7 换。在实际应用中通常采用快速傅里叶变换以高效计算DFT。
     8 */
     9 int dftExample(void) {
    10     cv::Mat image = cv::imread("sky.jpg", cv::IMREAD_COLOR);
    11     //assert(!image.empty(), "Failed read!");
    12     cv::Mat padded;
    13     // getOptimalDFTSize函数返回给定向量尺寸的傅里叶最优尺寸大小。
    14     // 此函数的唯一一个参数为int类型的vecsize,向量尺寸,即图片的rows、cols
    15     int m = cv::getOptimalDFTSize(image.rows);
    16     int n = cv::getOptimalDFTSize(image.cols);
    17     // 扩展输入图像image尺寸,在边缘加0值
    18     // 滤波 https://blog.csdn.net/qianqing13579/article/details/42323397
    19     cv::copyMakeBorder(image, padded, 0, m - image.rows, 0, n - image.cols, cv::BORDER_CONSTANT, cv::Scalar::all(0));
    20 
    21     cv::Mat planes[] = { cv::Mat_<float>(padded), cv::Mat::zeros(padded.size(), CV_32F) };
    22     cv::Mat complexImage;
    23     cv::merge(planes, 2, complexImage);  // 图像通道的合并
    24 
    25     cv::dft(complexImage, complexImage); // 对一维或者二维浮点数数组进行正向或反向离散傅里叶变换
    26     // 运行到此处 抛出异常 程序终止了
    27 
    28 
    29 
    30     cv::split(complexImage, planes);
    31     // 计算二维矢量的幅值:magnitude()函数
    32     // https://blog.csdn.net/qq_31935691/article/details/71699582
    33     cv::magnitude(planes[0], planes[1], planes[0]);
    34     cv::Mat magI = planes[0];
    35     magI += cv::Scalar::all(1);
    36     cv::log(magI, magI);
    37 
    38     magI = magI(cv::Rect(0, 0, magI.cols & -2, magI.rows & -2));
    39     int cx = magI.cols / 2;
    40     int cy = magI.rows / 2;
    41 
    42     // 将magI从横竖中间线切开 分为四部分
    43     cv::Mat q0(magI, cv::Rect(0, 0, cx, cy));     // 左上
    44     cv::Mat q1(magI, cv::Rect(cx, 0, cx, cy));    // 右上
    45     cv::Mat q2(magI, cv::Rect(0, cy, cx, cy));    // 左下
    46     cv::Mat q3(magI, cv::Rect(cx, cy, cx, cy));   // 右下
    47 
    48     cv::Mat tmp;
    49     // 交换q0 q3
    50     q0.copyTo(tmp);
    51     q3.copyTo(q0);
    52     tmp.copyTo(q3);
    53     // 交换q1 q2
    54     q1.copyTo(tmp);
    55     q2.copyTo(q1);
    56     tmp.copyTo(q2);
    57 
    58     // 归一化数据。该函数分为范围归一化与数据值归一化。
    59     // https://blog.csdn.net/cosmispower/article/details/64457406
    60     cv::normalize(magI, magI, 0, 1, cv::NORM_MINMAX);
    61 
    62     cv::imshow("Input Image", image);
    63     cv::imshow("Spectrum Magnitude", magI);
    64 
    65     cv::waitKey(0);
    66     return 0;
    67 }
    // OpenCV中的英特尔IPP异步C/C++库
    void ippasyncExample() {
    
    }
    
    // 使用OpenCV parallel_for 来并行化代码
    void parallelForExample() {
    
    }

    滤波操作

     1 class SmoothingDemo {
     2     // OpenCV平滑图像
     3     // 平滑 也称为模糊 是一种常用的图像处理操作 使用平滑的原因有很多 此处是为了减少噪音
     4     // 要执行平滑操作 需要对图像应用滤波器
     5     // 有多种类型的滤波器 最常见的是线性滤波器 除此之外还有
     6     // 归一化框滤波器 
     7     // 高斯滤波器
     8     // 中值滤波器
     9     // 双边滤波器
    10 public:
    11     SmoothingDemo() {
    12         windowName = "Smoothing Demo";
    13         cv::namedWindow(windowName, cv::WINDOW_AUTOSIZE);
    14     }
    15 
    16     int showDifferentSmoothing() {
    17         src = cv::imread("angel.jpg", cv::IMREAD_COLOR);
    18         // show original image
    19         if (displayCaption("Original Image") != 0)
    20             return 0;
    21 
    22         dst = src.clone();
    23         if (displayDst(DELAY_CAPTION) != 0)  // 展示clone后的目标图片
    24             return 0;
    25 
    26         // // 归一化滤波
    27         if (displayCaption("Homogeneous Blur") != 0)
    28             return 0;
    29         for (int i = 1; i < MAX_KERNEL_LENGTH; i += 2) {
    30             cv::blur(src, dst, cv::Size(i, i), cv::Point(-1, -1)); // https://blog.csdn.net/duwangthefirst/article/details/79971322
    31             if (displayDst(DELAY_BLUR) != 0)
    32                 return 0;
    33         }
    34 
    35         // 高斯滤波
    36         if (displayCaption("Gaussian Blur") != 0)
    37             return 0;
    38         for (int i = 1; i < MAX_KERNEL_LENGTH; i += 2) {
    39             cv::GaussianBlur(src, dst, cv::Size(i, i), 0, 0);  // https://blog.csdn.net/cindywry/article/details/102837184
    40             if (displayDst(DELAY_BLUR) != 0)
    41                 return 0;
    42         }
    43 
    44         // 中值滤波
    45         if (displayCaption("Median Blur") != 0)
    46             return 0;
    47         for (int i = 1; i < MAX_KERNEL_LENGTH; i += 2) {
    48             cv::medianBlur(src, dst, i);  // https://blog.csdn.net/charce_you/article/details/100177628
    49             if (displayDst(DELAY_BLUR) != 0)
    50                 return 0;
    51         }
    52 
    53         // 双边滤波
    54         if (displayCaption("Bilateral Blur") != 0)
    55             return 0;
    56         for (int i = 1; i < MAX_KERNEL_LENGTH; i += 2) {
    57             cv::bilateralFilter(src, dst, i, i * 2, i / 2);  // https://blog.csdn.net/keith_bb/article/details/54427779
    58             if (displayDst(DELAY_BLUR) != 0)
    59                 return 0;
    60         }
    61 
    62         // 随着上述各个for循环的进行 i 的增大 图片越来越模糊
    63 
    64         displayCaption("End: Press a key!");
    65         cv::waitKey(0);
    66         return 0;
    67     }
    68 
    69 private:
    70     int displayCaption(const char* caption) {
    71         dst = cv::Mat::zeros(src.size(), src.type());
    72         cv::putText(dst, caption, cv::Point(src.cols / 4, src.rows / 2), cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(255, 255, 255));
    73         cv::imshow(windowName, dst);
    74         int c = cv::waitKey(DELAY_CAPTION);
    75 
    76         if (c >= 0)
    77             return -1;
    78         return 0;
    79     }
    80 
    81     int displayDst(int delay) {
    82         cv::imshow(windowName, dst);
    83         int c = cv::waitKey(delay);
    84 
    85         if (c >= 0)
    86             return -1;
    87         return 0;
    88     }
    89 
    90     static const int DELAY_CAPTION = 1500;
    91     static const int DELAY_BLUR = 100;
    92     static const int MAX_KERNEL_LENGTH = 31;
    93     string windowName;
    94     cv::Mat src;
    95     cv::Mat dst;
    96 };

    侵蚀、扩张

     1 // 侵蚀 使图像中暗去增长
     2 // 扩张 使图像中亮区增长
     3 cv::Mat src;
     4 cv::Mat erosionDst;
     5 cv::Mat dilationDst;
     6 int erosionElem = 0;
     7 int erosionSize = 0;
     8 int dilationElem = 0;
     9 int dilationSize = 0;
    10 const int maxElem = 2;
    11 const int maxKernelSize = 21;
    12 
    13 static void Erosion(int, void*) {
    14     int erosionType = 0;
    15     if (erosionElem == 0)
    16         erosionType = cv::MORPH_RECT;
    17     else if (erosionElem == 1)
    18         erosionType = cv::MORPH_CROSS;
    19     else if (erosionElem == 2)
    20         erosionType = cv::MORPH_ELLIPSE;
    21     else {}
    22 
    23     // cv::getStructuringElement()返回指定形状和尺寸的结构元素
    24     // https://blog.csdn.net/kksc1099054857/article/details/76569718
    25     cv::Mat element = cv::getStructuringElement(erosionType, cv::Size(2 * erosionSize + 1, 2 * erosionSize + 1), cv::Point(erosionSize, erosionSize));
    26     // erode()函数可以对输入图像用特定结构元素进行腐蚀操作,该结构元素确定腐蚀操作过程中的邻域的形状,各点像素值将被替换为对应邻域上的最小值
    27     // https://blog.csdn.net/duwangthefirst/article/details/79999856
    28     cv::erode(src, erosionDst, element);
    29     cv::imshow("Erosion Demo", erosionDst);
    30 }
    31 
    32 static void Dilation(int, void*) {
    33     int dilationType = 0;
    34     if (dilationElem == 0)
    35         dilationType = cv::MORPH_RECT;
    36     else if (dilationElem == 1)
    37         dilationType = cv::MORPH_CROSS;
    38     else if (dilationElem == 2)
    39         dilationType = cv::MORPH_ELLIPSE;
    40     else {}
    41 
    42     cv::Mat element = cv::getStructuringElement(dilationType, cv::Size(2 * dilationSize + 1, 2 * dilationSize + 1), cv::Point(dilationSize, dilationSize));
    43     // dilate()函数可以对输入图像用特定结构元素进行膨胀操作,该结构元素确定膨胀操作过程中的邻域的形状,各点像素值将被替换为对应邻域上的最大值:
    44     // https://blog.csdn.net/duwangthefirst/article/details/80001106
    45     cv::dilate(src, dilationDst, element);
    46     cv::imshow("Dilation Demo", dilationDst);
    47 }
    48 
    49 int ErosionAndDilationExample(void) {
    50     src = cv::imread("blackWord.png", cv::IMREAD_COLOR);
    51     if (src.empty()) {
    52         std::cout << "Failed Read!" << std::endl;
    53         return -1;
    54     }
    55 
    56     cv::namedWindow("Erosion Demo", cv::WINDOW_AUTOSIZE);
    57     cv::namedWindow("Dilation Demo", cv::WINDOW_AUTOSIZE);
    58 
    59     // 此处最后一个参数不匹配?
    60     // 但是这个是void Fun(int, void*);类型的
    61     cv::createTrackbar("Element:
     0: Rect 
     1: Cross 
     2: Ellipse", "Erosion Demo", &erosionElem, maxElem, Erosion);
    62     cv::createTrackbar("Kernel size:
     2n + 1", "Erosion Demo", &erosionSize, maxKernelSize, Erosion);
    63 
    64     cv::createTrackbar("Element:
     0: Rect 
     1: Cross 
     2: Ellipse", "Dilation Demo", &dilationElem, maxElem, Dilation);
    65     cv::createTrackbar("Kernel size:
     2n + 1", "Dilation Demo", &dilationSize, maxKernelSize, Dilation);
    66 
    67     Erosion(0, 0);
    68     Dilation(0, 0);
    69     cv::waitKey(0);
    70     return 0;
    71 }
  • 相关阅读:
    [置顶] 【玩转cocos2d-x之二十】从CCObject看cocos2d-x的内存管理机制
    android 随手记 读写文件的几种方式
    (队列的应用5.3.2)POJ 2259 Team Queue(队列数组的使用)
    iPhone调用ffmpeg2.0.2解码h264视频的示例代码
    android 随手记 仿微信的popwindow
    [LeetCode] Remove Nth Node From End of List
    [置顶] Zend Optimizer 和 Zend Debugger 同时安装
    uva 10721
    android实现六边形等不规则布局
    WPF中的TextBox隐藏边框
  • 原文地址:https://www.cnblogs.com/lnlin/p/13771001.html
Copyright © 2020-2023  润新知