关于图像降色彩后,彩色直方图统计与实际像素值不匹配问题
2017-05-06 10:54
513 查看
一、先来看一个通过图像遍历进行图像降彩色(Color Reduce)的例子:
遍历图像的最基本方式:at<typename>(i,j)
Mat类提供了一个at的方法用于取得图像上的点,它是一个模板函数,可以取到任何类型的图像上的点。下面我们通过一个图像处理中的实际来说明它的用法。在实际应用中,我们很多时候需要对图像降色彩,因为256*256*256实在太多了,在图像颜色聚类或彩色直方图时,我们需要用一些代表性的颜色代替丰富的色彩空间,我们的思路是将每个通道的256种颜色用64种代替,即将原来256种颜色划分64个颜色段,每个颜色段取中间的颜色值作为代表色。
void colorReduce(Mat& image, int div) { //split(image, channelsRGB); for (int i = 0; i<image.rows; i++) { for (int j = 0; j<image.cols; j++) { image.at<Vec3b>(i, j)[0] = image.at<Vec3b>(i, j)[0] / div*div + div / 2; image.at<Vec3b>(i, j)[1] = image.at<Vec3b>(i, j)[1] / div*div + div / 2; image.at<Vec3b>(i, j)[2] = image.at<Vec3b>(i, j)[2] / div*div + div / 2; } } }
int main() { Mat image = imread("123.jpg"); imshow("input",image); colorReduce(image, 64); waitKey(0); imshow("output", image); cout << image << endl; waitKey(0); return 0; }
可见图像经过降色彩(Color Reduce)后,像素值只有“32,96,160,224”共四个值。
二、下面再看一个图像彩色直方图统计的例子:
HistogramND.hpp#include<opencv2\opencv.hpp> #include<iostream> using namespace std; using namespace cv; class HistogramND{ private: Mat image;//源图像 int hisSize[1], hisWidth, hisHeight;//直方图的大小,宽度和高度 float range[2];//直方图取值范围 const float *ranges; //Mat channelsRGB[3];//分离的BGR通道 vector<Mat> channelsRGB; MatND outputRGB[3];//输出直方图分量 public: HistogramND(){ hisSize[0] = 256; hisWidth = 400; hisHeight = 400; range[0] = 0.0; range[1] = 255.0; ranges = &range[0]; } //导入图片 bool importImage(String path){ image = imread(path); //bool importImage(Mat path){ image = imread(path); // path.copyTo(image); if (!image.data) return false; return true; } //分离通道 void splitChannels(){ split(image, channelsRGB); //cout << channelsRGB.at(0) << endl; } //计算直方图 void getHistogram(){ //calcHist(&channelsRGB[0], 1, 0, Mat(), outputRGB[0], 1, hisSize, &ranges); //calcHist(&channelsRGB[1], 1, 0, Mat(), outputRGB[1], 1, hisSize, &ranges); //calcHist(&channelsRGB[2], 1, 0, Mat(), outputRGB[2], 1, hisSize, &ranges); calcHist(&channelsRGB.at(0), 1, 0, Mat(), outputRGB[0], 1, hisSize, &ranges); calcHist(&channelsRGB.at(1), 1, 0, Mat(), outputRGB[1], 1, hisSize, &ranges); calcHist(&channelsRGB.at(2), 1, 0, Mat(), outputRGB[2], 1, hisSize, &ranges); //cout << channelsRGB[0] << endl; //输出各个bin的值 for (int i = 0; i < hisSize[0]; ++i){ cout << i << " B:" << outputRGB[0].at<float>(i); cout << " G:" << outputRGB[1].at<float>(i); cout << " R:" << outputRGB[2].at<float>(i) << endl; } } //显示直方图 void displayHisttogram(){ Mat rgbHist[3]; for (int i = 0; i < 3; i++) { rgbHist[i] = Mat(hisWidth, hisHeight, CV_8UC3, Scalar::all(0)); } normalize(outputRGB[0], outputRGB[0], 0, hisWidth - 20, NORM_MINMAX); normalize(outputRGB[1], outputRGB[1], 0, hisWidth - 20, NORM_MINMAX); normalize(outputRGB[2], outputRGB[2], 0, hisWidth - 20, NORM_MINMAX); for (int i = 0; i < hisSize[0]; i++) { int val = saturate_cast<int>(outputRGB[0].at<float>(i)); rectangle(rgbHist[0], Point(i * 2 + 10, rgbHist[0].rows), Point((i + 1) * 2 + 10, rgbHist[0].rows - val), Scalar(0, 0, 255), 1, 8); val = saturate_cast<int>(outputRGB[1].at<float>(i)); rectangle(rgbHist[1], Point(i * 2 + 10, rgbHist[1].rows), Point((i + 1) * 2 + 10, rgbHist[1].rows - val), Scalar(0, 255, 0), 1, 8); val = saturate_cast<int>(outputRGB[2].at<float>(i)); rectangle(rgbHist[2], Point(i * 2 + 10, rgbHist[2].rows), Point((i + 1) * 2 + 10, rgbHist[2].rows - val), Scalar(255, 0, 0), 1, 8); } cv::imshow("R", rgbHist[0]); imshow("G", rgbHist[1]); imshow("B", rgbHist[2]); imshow("image", image); } }; // int main(){ // string path = "1.jpg"; // HistogramND hist; // if (!hist.importImage(path)){ // cout << "Import Error!" << endl; // return -1; // } // hist.splitChannels(); // hist.getHistogram(); // hist.displayHisttogram(); // waitKey(0); // return 0; // } //void run(Mat path){ void run(String path){ HistogramND hist; if (!hist.importImage(path)){ cout << "Import Error!" << endl; //return -1; } hist.splitChannels(); hist.getHistogram(); hist.displayHisttogram(); waitKey(0); }
该程序通过split分离BRG三通道,再用calcHist来对三通道直方图进行统计。将此头文件include到刚才的cpp文件中,并对Main函数进行相应修改:
int main() { Mat image = imread("123.jpg"); imshow("input",image); colorReduce(image, 64); waitKey(0); imshow("output", image); imwrite("output.jpg",image); run("output.jpg"); waitKey(0); return 0; }
可见BGR三通道像素值并不是如刚才进行图像降色彩(Color Reduce)后所得的结果,在非“32,96,160,224”也不为0。
三、分析问题:
(1)设想1:统计直方图程序错误将HistogramND.hpp run函数中统计直方图部分和显示直方图
hist.getHistogram(); hist.displayHisttogram();屏蔽掉之后,再打印B通道像素值发现其在非“32,96,160,224”也不为0。
于是怀疑是图像色彩三通道分离split的问题。
(2)设想2:色彩三通道分离split问题
为了对比,直接在cpp文件中main函数中用split做三通道分离,再打印B通道像素值又发现其为“32,96,160,224”这四个值。
于是怀疑是HistogramND.hpp文件预处理的问题。
(3)设想3:HistogramND.hpp文件预处理问题
将HistogramND.hpp预处理和定义中多次修改后对比后发现此处不存在问题。
于是怀疑是main函数中存在问题。
(4)设想4:cpp文件中main函数问题
经多次验证后发现,在得到输出Mat
image后,在用hpp文件对图像进行处理时,是先在cpp文件中使用imwrite("output.jpg",image)函数后,再在hpp文件中使用用imread函数将图片读取后进行处理。
而图片存储为jpg格式后,会进行压缩,以至于图像经过
imwrite 再 imread 之后像素值发生了一定变化。
于是确定最终的问题为图片存储为jpg格式后的压缩导致像素值变化。
四、解决问题:
(1)将图片保存为bmp格式当图片存储为bmp格式时,不会被压缩,图像像素值也不会被改变。
int main() { Mat image = imread("123.jpg"); imshow("input",image); colorReduce(image, 64); waitKey(0); imshow("output", image); imwrite("output.bmp", image); run("output.bmp"); waitKey(0); return 0; }
然后再用hpp文件中的直方图统计方法得到如下结果:
(2)程序中读取图像文件直接修改为读取Mat
//导入图片
//bool importImage(String path){
// image = imread(path);
bool importImage(Mat path){
path.copyTo(image);
if (!image.data)
return false;
return true;
}
void run(Mat path){
//void run(String path){
HistogramND hist;
if (!hist.importImage(path)){
cout << "Import Error!" << endl;
//return -1;
}
hist.splitChannels();
hist.getHistogram(); hist.displayHisttogram();
waitKey(0);
}
int main() { Mat image = imread("123.jpg"); imshow("input",image); colorReduce(image, 64); waitKey(0); imshow("output", image); run(image); waitKey(0); return 0; }
相关文章推荐
- VTK修炼之道29:图像统计_彩色直方图计算
- 统计一副彩色图像实际使用的颜色数
- 关于Kinect根据深度图对齐彩色图抠人比彩色图像人大的问题
- 关于Kinect根据深度图对齐彩色图抠人比彩色图像人大的问题
- 关于Access中“标准表达式中数据类型不匹配”的问题
- 关于MATLAB图像相关性分析的问题
- 关于Web页中的色彩反转遇到一点问题
- 关于数字图像处理中灰度化的问题
- 关于httpcontext实际使用时出现的一个问题
- Delphi图像处理 -- 真彩色图像转换为低色彩图像
- 关于色彩管理的若干个问题
- 生成水印图片是出现这个问题!(无法从带有索引像素格式的图像创建 Graphics 对象。)
- 关于图像生成略缩图的问题,
- Matlab关于批量读取和存储图像这类问题的经验分享
- 关于cout,wcout输出的测试,以及printf,wprintf 输出中文,内存中直接输出图像给网页问题
- 关于条带引用图像参数集的问题
- 将JPG格式的彩色图像文件灰度化并进行直方图均衡
- 关于统计的一个sql问题,使用动态sql语句实现。
- 关于httpcontext实际使用时出现的一个问题
- 一组关于手持移动设备使用安全问题的统计数据