<aside> <img src="/icons/condense_yellow.svg" alt="/icons/condense_yellow.svg" width="40px" /> C++ | 数学 | 逻辑 | 按位转换 | 隐写术 | 最低有效位编码策略 | 对比增强 | 线性变换 | 非线性 | 直方图 | 累计 | 直方图均衡 | 概率分布 | 灰度 | 形态学 | 膨胀算子 | 腐蚀算子 | 开运算 | 闭运算 | 滤波器 | 克莱默-布鲁克纳滤波器 | 细化算法 | 骨架化 | 空间过滤 | 离散卷积 | 低通 | 高通 | 一阶导数 | 二阶导数 | Nagao滤波 | 拉普拉斯 | 自适应滤波 | 西格玛滤波 | 自适应窗口 | Deriche 轮廓滤波 | 分贝 | 频域滤波 | 傅里叶 | 莫列波纹 | 线性扩散 | 方程 | 算法 | 视频序列 | 高斯窗口 | 角点检测 | 纹理光谱 | Tamura 系数 | 粗糙度 | 局部二值模式 | 图像分割 | 动作分析 | 多光谱 | 成像捕捉 | 网格 | 变换压缩 | 断层 | 立体视觉 | 径向基函数

</aside>

🎯要点

🎯图像的数学转换 | 🎯按位转换,使用最低有效位编码策略的隐写术 | 🎯对比增强线性变换数学定义 | 🎯直方图运算:灰度概率分布,累计直方图,直方图均衡

🎯数学形态学:🖊膨胀和腐蚀算子逻辑数学定义和C++代码,🖊开运算和闭运算逻辑数学定义及C++代码,🖊克莱默-布鲁克纳滤波器逻辑数学定义及C++代码,🖊交替顺序滤波器逻辑数学定义及C++代码,🖊形态梯度数学逻辑定义及C++代码,🖊细化(骨架化)形态学技术逻辑关系及C++代码,🖊细化算法C++代码

🎯空间过滤:离散卷积逻辑数学定义和C++代码,🖊低通滤波器C++方法,🖊高通滤波器的一阶导数滤波C++方法,🖊二阶导数滤波C++拉普拉斯方法,🖊自适应滤波器C++西格玛滤波方法,🖊自适应窗口滤波器C++ Nagao 滤波方法,C++桑原非利斯托尔滤波方法,🖊Deriche 轮廓滤波器逻辑数学定义和C++代码,🖊Deriche 轮廓滤波器应用于二维图像,🖊计算梯度范数,🖊二阶Deriche 轮廓滤波器对图像拉普拉斯计算,🖊快速傅里叶变换C++代码,应用于两幅图傅里叶变换的模和参数混合,🖊图像光谱的可视化C++代码,以分贝为单位,🖊频域滤波:高斯滤波逻辑数学定义和C++代码,🖊莫列图像的处理,数学关系变换和C++代码去除莫列波纹,🖊线性扩散滤波数学方程和C++代码,🖊非线性扩散滤波C++代码二维上实现 Perona 和 Malik 算法,🖊视频序列上的非线性扩散滤波器C++代码。

🎯特征提取:C++实现高斯窗口,使用 Harris 和 Stephens 算法的实现角点检测,🖊兴趣点的亚像素检测线性系统数学定义和C++实现,🖊霍夫变换:C++对累加器网格进行阈值化,C++直线检测的霍夫变换,🖊圆和椭圆检测:C++计算圆检测的累加器,🖊纹理特征:纹理光谱数学定义及C++实现,🖊Tamura 系数和Tamura对比度C++代码,🖊粗糙度数学定义和C++使用积分图像的局部平均值,🖊C++绝对差异计算,🖊C++Tamura粗糙度计算,🖊纹理的方向性数学定义及C++Tamura的方向计算,🖊局部二值模式和对比度数学定义和C++实现,🖊C++使用局部二值模式串联直方图。

🎯图像分割 | 🎯二维和三维动作分析 | 🎯多光谱成像捕捉 | 🎯可视化和渲染三维网格对象 | 🎯通过变换压缩 | 🎯断层重建 | 🎯立体视觉图像分析 | 🎯使用径向基函数交互式变形

✂️梗概

🍇C++灰度处理和滤镜函数使用

我们将使用 C++ 和 OpenCV 来读取图像并显示结果。首先,让我们编写一个简单的 C++ 程序来读取来自相机的流并使用 OpenCV 显示 RGB 和灰度图像。

 #include <iostream>
 #include "opencv2/opencv.hpp"
 
 int main() {
     cv::VideoCapture cam(0);
     if (!cam.isOpened()) {
         throw std::runtime_error("Error");
     }
 
     cv::namedWindow("Window");
     while (true) {
         cv::Mat frame;
         cam >> frame;
         cv::resize(frame, frame, cv::Size(400, 400));
         cv::imshow("bgr_frame", frame);
         cv::Mat gray_frame;
         cv::cvtColor(frame, gray_frame, CV_BGR2GRAY);
         cv::imshow("gray_frame", gray_frame);
         if (cv::waitKey(30) >= 0) break;
     }
 }
 

我们要在类里安排我们的工作,我们将其称为 ImageOperator。

 class ImageOperator{
 public:
     ImageOperator() = default;
     ~ImageOperator() = default;

     static void to_gray_m1(const cv::Mat& input, cv::Mat& output);
     static void to_gray_m2(const cv::Mat& input, cv::Mat& output);
     static void to_gray_m3(const cv::Mat& input, cv::Mat& output);
     static void to_gray(const unsigned char* input,
                         const int width,
                         const int height,
                         const int channel,
                         unsigned char* output);
 };
 

您可能注意到,我们在第 6 行到第 9 行中声明了四个函数,用于将 RGB 图像转换为灰度图像。

前三个函数以 OpenCV Mat 矩阵作为输入参数。 我们将探索三种不同的方法将图像转换为灰度。 最后一个函数 to_gray 使用原始 C unsigned char 指针。我们将使用加权方法将 RGB 图像转换为灰度图像。执行此操作的等式是:gray_image = ( (0.3 * R) + (0.59 * G) + (0.11 * B) ).

使用迭代器

它也被称为安全方法。它不如其他方法有效,但它使循环像素变得更加容易。

 void ImageOperator::to_gray_m1(const cv::Mat &input, cv::Mat &output) {

     unsigned char *data_out = (unsigned char*)(output.data);
     int ind = 0;
     auto end = input.end<cv::Vec3b>();
     cv::MatConstIterator_<cv::Vec3b> it = input.begin<cv::Vec3b>();
     for (; it != end; ++it) {
         const unsigned char &r = (*it)[2];
         const unsigned char &g = (*it)[1];
         const unsigned char &b = (*it)[0];
         data_out[ind] = 0.3*r+0.59*g+0.11*b;
         ind++;
     }
 
 }
 

我们使用 cv::Vec3b 是因为每个元素由三个通道 bgr(蓝色、绿色和红色)组成,每个通道都是 1 字节,因此我们需要 3 字节。 输出 Mat 仅包含一个通道,并且具有与输入 Mat 相同的大小(行数和列数),因此我们可以访问其原始 unsigned char 指针数据并对其进行修改。

使用原始指针和总大小