【OpenCV计算机视觉编程攻略】三种操作像素的方法

  1. 准备工作
    为了说明图像扫描的过程, 我们来做一个简单的任务: 减少图像中颜色的数量。彩色图像由三通道像素组成, 每个通道表示红、 绿、 蓝三原色中一种颜色的亮度值, 每个数值都是8位的无符号字符类型, 因此颜色总数为256 × 256 × 256, 即超过1600万种颜色。 因此, 为了降低分析的复杂性, 有时需要减少图像中颜色的数量。 一种实现方法是把RGB空间细分到大小相等的方块中。 例如, 如果把每种颜色数量减少到1/8,那么颜色总数就变为32 × 32 × 32。 将旧图像中的每个颜色值划分到一个方块, 该方块的中间值就是新的颜色值; 新图像使用新的颜色值,颜色数就减少了。因此基本的减色算法很简单。 假设N是减色因子, 将图像中每个像素的每个通道的值除以N(使用整数除法, 不保留余数) 。 然后将结果乘以N, 得到N的倍数, 并且刚好不超过原始像素值。 只需加上N /2, 就得到相邻的N倍数之间的中间值。 对所有8位通道值重复这个过程, 就会得到(256 / N) × (256 / N) × (256 / N)种可能的颜色值。(摘录自:OpenCV计算机视觉编程攻略)
  2. 算法实现
    //colorReduce.hpp
    #include <iostream>
    
    #include <opencv2/core/core.hpp>
    #include <opencv2/imgproc/imgproc.hpp>
    
    using namespace std;
    using namespace cv;
    
    class colorReduce {
    public:
    	int div;
    	colorReduce():div(64){};
    	colorReduce(int div):div(div){};
    	~colorReduce(){};
    	void colorReduce0(Mat& src, Mat& des);
    	void colorReduce1(Mat& src, Mat& des);
    	void colorReduce2(Mat& src, Mat& des);
    
    private:
    	bool check(Mat& src, Mat& des);
    };

    头文件中主要使用了三种不同的方法来访问像素,减色原理都是相同的,下面是算法实现:

    //colorReduce.cpp
    #include "colorReduce.hpp"
    
    #include <iostream>
    
    #include <opencv2/core/core.hpp>
    #include <opencv2/imgproc/imgproc.hpp>
    
    using namespace std;
    using namespace cv;
    
    bool colorReduce::check(Mat& src, Mat& des) {
    	if (src.empty()) {
    		cout << "invalid image" << endl;
    		return 1;
    	}
    
    	des.create(Size(src.cols, src.rows), src.type());
    
    	if (des.rows < src.rows || des.cols < src.cols || des.type() != src.type()) {
    		cout << "target imgae is too small!" << endl;
    		return 1;
    	}
    
    	return 0;
    }
    
    void colorReduce::colorReduce0(Mat& src, Mat& des) {
    	if(!check(src, des)) {
    		int rows = src.rows;
    		int cols = src.cols;
    
    		for (int i=0; i<rows; i++) {
    			for (int j=0; j<cols; j++) {
    				des.at<Vec3b>(i,j)[0] = src.at<Vec3b>(i,j)[0]/div*div + div/2;
    				des.at<Vec3b>(i,j)[1] = src.at<Vec3b>(i,j)[1]/div*div + div/2;
    				des.at<Vec3b>(i,j)[2] = src.at<Vec3b>(i,j)[2]/div*div + div/2;
    			}
    		}
    	}
    }
    
    void colorReduce::colorReduce1(Mat& src, Mat& des) {
    	if(!check(src, des)) {
    		int rows = src.rows;
    		int nc = src.step;
    
    		for (int i=0; i<rows; i++) {
    			uchar * srcptr = src.ptr<uchar>(i);
    			uchar * desptr = des.ptr<uchar>(i);
    			for (int j=0; j<nc; j++) {
    				desptr[j] = srcptr[j]/div*div + div/2;
    			}
    		}
    	}
    }
    
    void colorReduce::colorReduce2(Mat& src, Mat& des) {
    	if(!check(src, des)) {
    		MatIterator_<Vec3b> it_src_begin = src.begin<Vec3b>();
    		MatIterator_<Vec3b> it_src_end = src.end<Vec3b>();
    		//等价于Mat_<Vec3b>::iterator it = src.begin();
    		//typedef MatIterator_<_Tp> iterator;
    		MatIterator_<Vec3b> it_des_begin = des.begin<Vec3b>();
    		//MatIterator_<Vec3b> it_des_end = des.end<Vec3b>();
    
    		for (; it_src_begin != it_src_end; it_src_begin++, it_des_begin++) {
    			(*it_des_begin)[0] = (*it_src_begin)[0]/div*div + div/2;
    			(*it_des_begin)[1] = (*it_src_begin)[1]/div*div + div/2;
    			(*it_des_begin)[2] = (*it_src_begin)[2]/div*div + div/2;
    		}
    	}
    }

    效果展示:

    原图
    效果图(div=128)

猜你喜欢

转载自blog.csdn.net/q_z_r_s/article/details/82781751