• 访问图像中的像素[OpenCV 笔记16]


    再更一发好久没更过的OpenCV,不过其实写到这个部分对计算机视觉算法有所了解的应该可以做到用什么查什么了,所以后面可能会更的慢一点吧,既然开了新坑,还是机器学习更有研究价值吧。。。

    图像在内存中的存储方式

    灰度图像

     

    RGB图像,矩阵的列会包含多个子列

    因为内存足够大,可以实现连续存储,因此,图像中的各行就能一行一行地连接起来,形成一个长行。连续存储,有助于提高图像扫面速度,可以使用isContinuous()来判断矩阵是否是连续存储。

    颜色空间缩减

    对于三通道图像,一个像素对应的颜色有一千六百多万种,用如此多的颜色可能会影响算法性能。颜色空间缩减即用颜色中具有代表性的一部分表示相近颜色,做法是:将现有颜色空间值除以某个输入值,以获得较少的颜色数。对每个像素进行乘除操作也需要浪费一定的时间(加,减,赋值等代价较低),对于较大的图像,可以预先计算所有可能的值,建立 look up table,

    int divideWidth = 10;
    uchar table[256];
    for (int i = 0; i < 256; ++i)
      table[i] = divideWidth * (i/divideWidth);

    然后遍历图像矩阵的每个像素,对像素应用公式:

    p[j] = table[p[j]];

    OpenCV官方提供了函数进行图像元素查找、扫描与操作图像

    void cv::LUT    (    InputArray     src,
                    InputArray     lut,
                    OutputArray     dst 
                  )    

    进行look-up table转换操作,输出矩阵将被赋值为

    dst(I)<-lut(src(I)+d)

    其中,当src为CV_8U时,d=0,src为CV_8S时,d=128(用于把look up table输入转换到0~255)

    • src:矩阵输入,矩阵元素为8-bit色彩值。
    • lut:256个色彩值的look-up table,如果src为多通道函数,lut可为单通道(src每通道的处理方式相同)或与src的通道数相同。 
    • dst:与输入矩阵大小、通道数相同的输出矩阵src, 类型与lut相同(CV_8U或CV_8S)

    用法示例如下,

    Mat lookUpTable(1, 256, CV_8U);
    uchar* p = lookUpTable.data;
    for(int i = 0; i < 256; ++i)
      p[i] = table[i];
    for(int i=0; i < times; ++i)
      LUT(Input,lookUpTable, Output);

    计时函数

    int64 getTickCount()

    返回CPU自某个事件(如启动电脑)以来走过的时钟周期

    double getTickFrequency()

    返回CPU一秒钟所走过的时钟周期数,这样我们就可以以秒为单位对某运算计时

    double time0 = stactic_cast<double>(getTickCount());
    time0 = ((double) getTickCount() - time0) / getTickFrequency();
    cout << "Runing time: " << time0 << "s" << endl;

    访问图像中像素的三类方法

    用指针访问像素

    利用C中的操作符[]或*,这种方法最快,但比较抽象。

     

    用迭代器操作像素

    类似于STL中的用法,只需获取图像矩阵的begin和end,然后迭代从begin直至end。比前一种方法安全,不会越界,但速度慢。

     

    动态地址计算

    简单明了,直接用at(y,x)找到像素点,但是速度最慢。

     

    上述三种方法的事例程序如下:

    #include <opencv2/opencv.hpp>
    #include <opencv2/highgui/highgui.hpp>
    #include <iostream>
    
    // function
    void colorReduce(cv::Mat& inputImage, cv::Mat& outputImage, int div);
    
    // main
    int main( int argc, char** argv )
    {
        // Load image
        cv::Mat srcImage = cv::imread("1.jpg");
        imshow("orginal image", srcImage);
        
        // alocate space for output image
        cv::Mat dstImage;
        dstImage.create(srcImage.rows, srcImage.cols, srcImage.type());
        
        // get the starting time
        double time0 = static_cast<double>(cv::getTickCount());
        
        // call color space reduction function
        colorReduce(srcImage, dstImage, 32);
        
        // estimate runing time
        time0 = ((double)cv::getTickCount() - time0)/cv::getTickFrequency();
        std::cout << "Running time for this method: " << time0 << "s." << std::endl;
        
        imshow("Lab Space", dstImage);
        cv::waitKey(0);
        
        return 0;
    }
    
    #define USESUBS
    #ifdef USEPOINTER
    void colorReduce(cv::Mat& inputImage, cv::Mat& outputImage, int div)
    {
        // set parameters
        outputImage = inputImage.clone();
        int rowNumber = outputImage.rows;
        int colNumber = outputImage.cols*outputImage.channels();
        
        for(int i = 0;i < rowNumber;i++)
        {
            uchar* data = outputImage.ptr<uchar>(i);
            // get the address of the ith row
            for(int j=0; j<colNumber; j++)
            {
                data[j] = data[j]/div*div + div/2;
            }
        }
        
    }
    #endif
    #ifdef USEITERATOR
    void colorReduce(cv::Mat& inputImage, cv::Mat& outputImage, int div)
    {
        // set parameters
        outputImage = inputImage.clone();
        
        // get the iterator
        cv::Mat_<cv::Vec3b>::iterator it = outputImage.begin<cv::Vec3b>();
        cv::Mat_<cv::Vec3b>::iterator itend = outputImage.end<cv::Vec3b>();
        
        // save new pixel colors
        for(;it != itend; ++it)
        {
            (*it)[0] = (*it)[0]/div*div + div/2; // B
            (*it)[1] = (*it)[1]/div*div + div/2; // G
            (*it)[2] = (*it)[2]/div*div + div/2; // R
        }
        
    }
    #endif
    #ifdef USESUBS
    void colorReduce(cv::Mat& inputImage, cv::Mat& outputImage, int div)
    {
        // set parameters
        outputImage = inputImage.clone();
        int rowNumber = outputImage.rows;
        int colNumber = outputImage.cols;
        
        // save new pixel colors
        for(int i=0; i<rowNumber; i++)
        {
            for(int j=0; j<colNumber; j++)
            {
                outputImage.at<cv::Vec3b>(i,j)[0] = outputImage.at<cv::Vec3b>(i,j)[0]/div*div + div/2; // B
                outputImage.at<cv::Vec3b>(i,j)[1] = outputImage.at<cv::Vec3b>(i,j)[1]/div*div + div/2; // G
                outputImage.at<cv::Vec3b>(i,j)[2] = outputImage.at<cv::Vec3b>(i,j)[2]/div*div + div/2; // R
            }
        }
        
    }
    #endif
    /*
      Outputs:
        USEPOINTER
            Running time for this method: 0.0162628s.
        USEITERATOR
            Running time for this method: 0.0362183s.
        USESUBS
            Running time for this method: 0.0518141s.
    */
  • 相关阅读:
    git环境搭建、git详细使用教程、快速上手git
    数据一致性解决方案实践
    锁的使用
    数据库连接池优化
    多级缓存优化实践
    服务端调优与JVM调优
    Sentinel 流量防卫兵
    Spring Cloud Gateway微服务网关
    OpenFeign与负载均衡
    Nacos config原理
  • 原文地址:https://www.cnblogs.com/Xiaoyan-Li/p/5792796.html
Copyright © 2020-2023  润新知