zoukankan      html  css  js  c++  java
  • OpenCV 学习之路(2) -- 操作像素

      本节内容:

    • 访问像素值
    • 用指针扫描图像
    • 用迭代器扫描图像
    • 编写高效的图像扫描循环
    • 扫描图像并访问相邻像素
    • 实现简单的图像运算
    • 图像重映射

     访问像素值

      准备工作:

        创建一个简单函数,用它在图像中加入椒盐噪声.

        实现如下:

    void salt(cv::Mat image, int n){
        int i, j;
        for(int k = 0; k < n; k ++){
            i = std::rand()%image.cols;     
            j = std::rand()%image.rows;     
    
            if(image.type() == CV_8UC1){ //灰度图 
                image.at<uchar>(j,i) = 255;
            }else {
                image.at<cv::Vec3b>(j,i)[0] = 255;
                image.at<cv::Vec3b>(j,i)[1] = 255;
                image.at<cv::Vec3b>(j,i)[2] = 255;
            }
        } 
    }

        完整代码:

    #include <cstdlib>
    #include <opencv2/core/core.hpp>
    #include <opencv2/highgui/highgui.hpp>
    void salt(cv::Mat image, int n){
        int i, j;
        for(int k = 0; k < n; k ++){
            i = std::rand()%image.cols;
            j = std::rand()%image.rows;
    
            if(image.type() == CV_8UC1){ //灰度图 
                image.at<uchar>(j,i) = 255;
            }else {
                image.at<cv::Vec3b>(j,i)[0] = 255;
                image.at<cv::Vec3b>(j,i)[1] = 255;
                image.at<cv::Vec3b>(j,i)[2] = 255;
            }
        }    
    }
    
    int main(){
        cv::Mat image = cv::imread("./data/rgb.png");
        salt(image,3000);
        cv::namedWindow("image");
        cv::imshow("Image", image);    
        cv::waitKey(0);
        cv::imwrite("./data/output.png", image);
        return 0;
    }
    View Code

        效果如图:

                   

     用指针扫描图像

      准备工作:

        先完成一个简单任务:减少图像中的颜色数量。

        原理:如果N是减少因子,那么对于像素的每一个频道,除以N(由于是整除,所以余数会丢失)。如果将结果再乘以N,那么结果将会小于原来的像素值。然后再加上N/2你将会获得两个相邻N倍数中间的那个数,然后你就得到了一个256/NX256/NX256/N颜色数的图像。下面是我们所写的函数,函数处理是in-place的,也就是说处理结果直接赋值给源图像,不占用额外的存储空间。

        代码:

    #include <opencv2/core/core.hpp>
    #include <opencv2/highgui/highgui.hpp>
    #include <iostream>
    
    
    void colorReduce(cv::Mat image, int div){
        int nl = image.rows;
        int nc = image.cols * image.channels();
        
        for(int j = 0; j < nl; j++){
            uchar* data = image.ptr<uchar>(j);
            for(int i = 0; i < nc; i++){
                data[i] = data[i]/div*div + div/2;    
            }
        }    
    }
    
    int main(){
        cv::Mat image = cv::imread("./data/beauty.jpg");
        colorReduce(image, 64);
        cv::namedWindow("Image");
        cv::imshow("Image",image);
        cv::waitKey(0);
        cv::imwrite("./data/output.jpg", image);
        return 0;
    }
    View Code

        补充:还可以使用为运算来计算data的值; 

           uchar mask = 0xFF<<n;             //例如:div = 16,则 mask = 0xF0

           *data &= mask;

           *data++ += div>>1; 

    处理前:                             处理后:                 

     

     用迭代器扫描图像

      准备工作:仍然使用上面减色程序。

           使用Mat_模板类内部定义的iterator类型 Mat_<cv::Vec3b>::iterator it;

       修改后的减色程序如下:

    void colorReduce(cv::Mat &image, int div){
        cv::Mat_<cv::Vec3b>::iterator it = image.begin<cv::Vec3b>();
        cv::Mat_<cv::Vec3b>::iterator itend = image.end<cv::Vec3b>(); 
        for( ; it != itend; ++it){
            (*it)[0] = (*it)[0]/div*div + div/2;
            (*it)[1] = (*it)[1]/div*div + div/2;
            (*it)[2] = (*it)[2]/div*div + div/2;
        }
    }
    View Code

      效果同上;

    编写高效的图像扫描循环

      

    在前面的章节,我们已经提到过了不同的访问图像像素的方法。现在我们将比较一下这些不同方法的效率。因为代码的效率执行时间是我们必须要考虑的。但是代码效率最大化带来来的往往是减少了代码的可读性。所以只要适当的在核心地方增加代码的效率。

    为了计算代码的执行时间,我们使用OpenCV中的cv::getTickCount()方法。这个方法给出从开机到现在的时钟周期数。因为我们想要的时间单位是毫秒,所以我们还要使用cv::getTickFrequency()方法。这个给出了每一秒的始终周期数。然后计算方法如下:

    double duration;  
    duration = static_cast<double>(cv::getTickCount());  
    colorReduce(image); // the function to be tested  
    duration = static_cast<double>(cv::getTickCount())-duration;  
    duration /= cv::getTickFrequency(); // the elapsed time in ms  

    最后得出的结果是:使用位计算得到的结果速度最快!

    扫描图像并访问相邻像素

      准备工作:

         这里使用一个锐化的处理函数. 如果从图像中减去拉普拉斯算子部分,图像的边缘就会放大,因而使图像更尖锐.

        用以下的方法计算锐化的数值:  sharpened_pixel = 5 * current -left - right - up -down;

      实现:

    /********************************************************
        > File name:sharpen    
        > author: yoyo 
        > Source from:xiang gao
        > time:2016.7.18 Monday 17:22
        > 
    *************************************************************/
    
    #include <opencv2/core/core.hpp>
    #include <opencv2/highgui/highgui.hpp>
    #include <iostream>
    
    using namespace std;
    
    void sharpen(const cv::Mat &image, cv::Mat &result){
        //判断是否需要分配图像数据
        result.create(image.size(), image.type());
        int nchannels = image.channels(); //获取通道数
    
        //处理除第一与最后行的所有行
        for(int j = 1; j < image.rows-1; j++){
            const uchar* previous = image.ptr<const uchar>(j-1);
            const uchar* current  = image.ptr<const uchar>(j);
            const uchar* next      = image.ptr<const uchar>(j+1);
            uchar* output = result.ptr<uchar>(j);
    
            for(int i = nchannels; i < (image.cols - 1)*nchannels; i++){
                *output++ = cv::saturate_cast<uchar>(5*current[i] - current[i-nchannels] - current[i+nchannels] -previous[i] -next[i]);
            }
        }
        result.row(0).setTo(cv::Scalar(0));
        result.row(result.rows-1).setTo(cv::Scalar(0));
        result.col(0).setTo(cv::Scalar(0));
        result.col(result.cols-1).setTo(cv::Scalar(0));
    }
    
    int main(int argc, char * argv[]){
    
        cv::Mat image = cv::imread("/home/yoyo/openCV/data/beauty.jpg");
        cv::Mat image1 = image;
        cv::imshow("image1", image1);
        sharpen(image1 ,image);
    //    cv::namedWindow("image");
        cv::imshow("Image", image);    
        cv::waitKey(0);
        cv::imwrite("/home/yoyo/openCV/data/sharpen.jpg", image);    
        return 0;
    }
    View Code

      效果:

        前:                      后:

                          

    实现简单的图像运算

      图像就是普通的矩阵,可以进行加减乘除运算,因此可以用多种不同的方式组合图像.

      准备工作:两张相等大小的图像;

       参考资料:http://www.opencv.org.cn/opencvdoc/2.3.2/html/doc/tutorials/core/adding_images/adding_images.html

      代码:

    #include <cv.h>
    #include <highgui.h>
    #include <iostream>
    
    using namespace cv;
    
    int main( int argc, char** argv )
    {
     double alpha = 0.5; double beta; double input;
    
     Mat src1, src2, dst;
    
     /// Ask the user enter alpha
     std::cout<<" Simple Linear Blender "<<std::endl;
     std::cout<<"-----------------------"<<std::endl;
     std::cout<<"* Enter alpha [0-1]: ";
     std::cin>>input;
    
     /// We use the alpha provided by the user iff it is between 0 and 1
     if( alpha >= 0 && alpha <= 1 )
       { alpha = input; }
    
     /// Read image ( same size, same type )
     src1 = imread("../../images/LinuxLogo.jpg");
     src2 = imread("../../images/WindowsLogo.jpg");
    
     if( !src1.data ) { printf("Error loading src1 
    "); return -1; }
     if( !src2.data ) { printf("Error loading src2 
    "); return -1; }
    
     /// Create Windows
     namedWindow("Linear Blend", 1);
    
     beta = ( 1.0 - alpha );
     addWeighted( src1, alpha, src2, beta, 0.0, dst);
    
     imshow( "Linear Blend", dst );
    
     waitKey(0);
     return 0;
    }
    View Code

    图像重映射

  • 相关阅读:
    git
    代理上网时git不能直接连接远程库的解决办法
    Python程序练习2--模拟三级菜单
    python os模块常用文件操作方法
    Python程序练习1-模拟用户登录验证
    牛牛牛图片胡乱下载
    oozie 4.1.0与4.2.0版本问题BUG
    hbase 协处理器,实现group by,distinct函数
    Js公共操作类 之 String 扩展方法介绍(一)
    CSS3之伪元素选择器和伪类选择器
  • 原文地址:https://www.cnblogs.com/yoyo-sincerely/p/5816118.html
Copyright © 2011-2022 走看看