C++数理逻辑定义和实现成像捕捉及交互式变形

54 篇文章 0 订阅
42 篇文章 0 订阅
本文详细介绍了使用C++和OpenCV进行图像处理的各种技术,包括灰度转换方法、数学形态学操作、滤波器应用、特征提取(如角点检测和纹理分析)、以及图像分割和二维动作分析等,展示了从基础操作到高级处理的全面内容。
摘要由CSDN通过智能技术生成

🎯要点

  1. 🎯图像的数学转换。
  2. 🎯按位转换,使用最低有效位编码策略的隐写术。
  3. 🎯对比增强线性变换数学定义。
  4. 🎯直方图运算:灰度概率分布,累计直方图,直方图均衡。
  5. 🎯数学形态学:🖊膨胀和腐蚀算子逻辑数学定义和C++代码,🖊开运算和闭运算逻辑数学定义及C++代码,🖊克莱默-布鲁克纳滤波器逻辑数学定义及C++代码,🖊交替顺序滤波器逻辑数学定义及C++代码,🖊形态梯度数学逻辑定义及C++代码,🖊细化(骨架化)形态学技术逻辑关系及C++代码,🖊细化算法C++代码。
  6. 🎯空间过滤:离散卷积逻辑数学定义和C++代码,🖊低通滤波器C++方法,🖊高通滤波器的一阶导数滤波C++方法,🖊二阶导数滤波C++拉普拉斯方法,🖊自适应滤波器C++西格玛滤波方法,🖊自适应窗口滤波器C++ Nagao 滤波方法,C++桑原非利斯托尔滤波方法,🖊Deriche 轮廓滤波器逻辑数学定义和C++代码,🖊Deriche 轮廓滤波器应用于二维图像,🖊计算梯度范数,🖊二阶Deriche 轮廓滤波器对图像拉普拉斯计算,🖊快速傅里叶变换C++代码,应用于两幅图傅里叶变换的模和参数混合,🖊图像光谱的可视化C++代码,以分贝为单位,🖊频域滤波:高斯滤波逻辑数学定义和C++代码,🖊莫列图像的处理,数学关系变换和C++代码去除莫列波纹,🖊线性扩散滤波数学方程和C++代码,🖊非线性扩散滤波C++代码二维上实现 Perona 和 Malik 算法,🖊视频序列上的非线性扩散滤波器C++代码。
  7. 🎯特征提取:C++实现高斯窗口,使用 Harris 和 Stephens 算法的实现角点检测,🖊兴趣点的亚像素检测线性系统数学定义和C++实现,🖊霍夫变换:C++对累加器网格进行阈值化,C++直线检测的霍夫变换,🖊圆和椭圆检测:C++计算圆检测的累加器,🖊纹理特征:纹理光谱数学定义及C++实现,🖊Tamura 系数和Tamura对比度C++代码,🖊粗糙度数学定义和C++使用积分图像的局部平均值,🖊C++绝对差异计算,🖊C++Tamura粗糙度计算,🖊纹理的方向性数学定义及C++Tamura的方向计算,🖊局部二值模式和对比度数学定义和C++实现,🖊C++使用局部二值模式串联直方图。
  8. 🎯图像分割,🎯二维和三维动作分析,🎯多光谱成像捕捉,🎯可视化和渲染三维网格对象,🎯通过变换压缩,🎯断层重建,🎯立体视觉图像分析,🎯使用径向基函数交互式变形。

🍇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 指针数据并对其进行修改。

使用原始指针和总大小

可以使用 data 属性访问 cv::Mat 的原始数据指针。图像的总字节数可以通过以下公式计算: img_size_in_byte = number_of_channels * img_width*img_height 因此,如果我们有 4040 bgr 图像,则其总大小为 34040 = 4800,相应的灰度图像大小为 140*40 = 1600。这里,我们假设每个通道需要一个字节。

每三个连续字节应转换为灰度图像中的一个值。

void ImageOperator::to_gray_m2(const cv::Mat &input, cv::Mat &output) {
    unsigned char *data_in = (unsigned char*)(input.data);
    unsigned char *data_out = (unsigned char*)(output.data);

    int index = 0;
    int byte_size = input.channels()*input.rows*input.cols;
    while(index!=byte_size){
        data_out[index/input.channels()] = unsigned(0.11*data_in[index]+0.59*data_in[index+1]+0.3*data_in[index+2]);

        index+=3;
    }
}

在上面的代码片段中,我们使用索引来循环 bgr 输入图像中的字节。我们还将每个循环的索引移动 3,直到它等于总大小(以字节为单位)。

在 for 循环中使用原始指针

图像数据以连续字节的形式存储在内存中。在此方法中,您可以使用其行和列坐标但从 1D 字符指针访问像素。input.step 给出一行中的总字节数。如果将其与行索引相乘,就可以获得指向特定行的指针。访问特定行后,可以使用 col 索引来访问特定列。换句话说:要访问 2D 数组中 x,y 位置的一个像素,可以编写 img ⁡ [ x ] [ y ] \operatorname{img}[ x ][ y ] img[x][y]。要在一维数组中获得相同的结果,必须使用 img ⁡ [ y ∗ \operatorname{img}\left[ y ^*\right. img[y step+x]。

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

    unsigned char *data_in = (unsigned char*)(input.data);
    unsigned char *data_out = (unsigned char*)(output.data);

    int index = 0;
    for (int row = 0; row < input.rows; ++row) {
        for (int col = 0; col < input.cols*input.channels(); col+=input.channels()) {
            data_out[index]= 0.11*data_in[row*input.step+col]+
                             0.59*data_in[row*input.step+col+1]+
                             0.3*data_in[row*input.step+col+2];
            index++;
        }
    }
}

前面的代码循环遍历 bgr 图像中的每 3 个字节并计算其比例值。

现在,在了解了前面的方法之后,您会发现将 RGB 图像转换为灰度图像非常简单。实际上,甚至不需要解释,因为正如您所注意到的,我们在方法 2 和 3 中使用了原始指针。

参阅一:计算思维
参阅二:亚图跨际
  • 18
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值