模拟Matlab显示图像的效果

VisualTool.h头文件

#ifndef _VISUALTOOL_H_
#define _VISUALTOOL_H_

#include "opencv2/opencv.hpp"

#define HIST_TYPE_MIX 0
#define HIST_TYPE_CONTOUR 1

namespace cv
{
	//深度显示单通道uchar,float, int类型图像,IMAGE_GRAYSCALE
	void ImageGrayScale(std::string windowName, const cv::Mat img);
	
	//以柱状图显示数组,array必须为 CV_32F,CV_32S,CV_8U中的一种,且rows == 1
	void ShowArrayHistogram(std::string title, cv::Mat array, cv::Size size = cv::Size(400,400));
	
	//显示一幅图像的直方图,histType为显示方式,
	//                      HIST_TYPE_MIX表示三通道混合显示,
	//                      HIST_TYPE_CONTOUR表示以轮廓显示
	void ShowImageHistogram(const std::string windowName, 
		                    const cv::Mat src, 
							const cv::Mat mask = cv::Mat(), 
							int histType = HIST_TYPE_MIX, 
							cv::Size windowSize = cv::Size(256, 200));
	
	//显示一幅图像的颜色分布图
	void ShowImageColorDistribution(const std::string windowName, 
		                              const cv::Mat src_3u,
		                              int nBins = 32, 
									   const cv::Mat mask = cv::Mat(), 
									   cv::Size windowSize = cv::Size(256, 200));

}
#endif

VisualTool.cpp :

#include "VisualTool.h"

namespace cv
{
	void ImageGrayScale(std::string windowName, const cv::Mat img){
		assert(img.channels() == 1 && !img.empty());
		/*if(!img.empty( )){
			std::cerr<<"Load File invalid....!"<<std::endl;
			exit(EXIT_SUCCESS);
		}
		if(img.channels() == 1){
			std::cerr<<"Load File is Gray Image!"<<std::endl;
			exit(EXIT_FAILURE);
		}*/
		
		//get min max value of the mat
		double minPixelValue, maxPixelValue;
		cv::minMaxIdx(img, &minPixelValue, &maxPixelValue);
		double valueRange = maxPixelValue - minPixelValue;
		
		//init color table
		const int minSaturation = 20;
		const int colorTableLength = (255 - minSaturation) * 4;    // r -> g -> b
		cv::Scalar colorTable[colorTableLength];
		
		int i,j;
		for (i = 0, j = minSaturation; i < colorTableLength / 4; i++, j++)
			colorTable[i] = CV_RGB(255, j, minSaturation);
		for (i = colorTableLength / 4, j=1; i < colorTableLength / 2; i++, j++)
			colorTable[i] = CV_RGB(255 - j, 255, minSaturation);
		for (i = colorTableLength/2, j=minSaturation; i < colorTableLength/4*3; i++, j++)
			colorTable[i] = CV_RGB(minSaturation, 255, j);
		for (i = colorTableLength/4*3, j=1; i < colorTableLength; i++, j++)
			colorTable[i] = CV_RGB(minSaturation, 255 - j, 255);
		
		//draw color table
		const int margin = 20;
		const int tableHeight = 300;
		const int tableWidth = 150;
		const int barWidth = 30;
		const int barHeight = tableHeight - margin * 2;
		float scale = (float)barHeight / colorTableLength;
		
		int imageHeight = cv::max(img.rows, tableHeight);
		int imageWidth  = img.cols + tableWidth;
		cv::Mat img3u( imageHeight, imageWidth, CV_8UC3, cv::Scalar::all(0));
		
		for (int i=0; i<barHeight; i++){
			cv::Point pt1(img.cols + margin, margin + i);
			cv::Point pt2(img.cols + margin + barWidth, margin + i);
			cv::line(img3u, pt1, pt2, colorTable[cvRound(i/scale)], 1);
		}
		
		//illustration
		for (int i=0; i<5; i++){
			float value = minPixelValue + i / 4.0 * valueRange;
			std::stringstream s;
			s<<value;
			int bx = img.cols + margin + barWidth;
			int by = tableHeight - margin - barHeight / 4 * i ;
			cv::line(img3u, cv::Point(bx+5, by), cv::Point(bx+10, by), cvScalarAll(255), 2);
			cv::putText(img3u, s.str(), cv::Point(bx + 20, by + 8),
				CV_FONT_HERSHEY_SIMPLEX, 0.6, cvScalarAll(255), 1);
		}
		
		//show image
		cv::Mat tim(img.size(), CV_32F);
		img.convertTo(tim, CV_32F);
		
		for (int y = 0; y < img.rows; y++){
			const float* srcData = tim.ptr<float>(y);
			cv::Vec3b* dstData = img3u.ptr<cv::Vec3b>(y);
			for (int x = 0; x<img.cols; x++){
				double pixel = (srcData[x] - minPixelValue) / valueRange;
				cv::Scalar color = colorTable[cvRound(pixel * (colorTableLength-1))];
				dstData[x] =cv::Vec3b(color.val[2], color.val[1], color.val[0]);
			}
		}
		cv::imshow(windowName, img3u);
		cv::imwrite("Lbp.jpg",img3u);
	}

	void ShowArrayHistogram(std::string title, cv::Mat hist, cv::Size size){
		CV_Assert(hist.rows == 1);
		cv::Mat imHist = cv::Mat::zeros(size, CV_8UC3);
		int nBins = hist.rows*hist.cols;
		double min, max;
		cv::minMaxLoc(hist, &min, &max);
		double bin_width=(double)size.width/nBins;  
		double bin_unith=(double)size.height/max;
		
		if(hist.type() == CV_32F){
			float * ptr = hist.ptr<float>(0);
			for(int i=0;i<nBins;i++){ 
				cv::Point p0=cv::Point(i*bin_width,size.height);  
				cv::Point p1=cv::Point((i+1)*bin_width,size.height-ptr[i]*bin_unith);  
				cv::rectangle(imHist, p0, p1, cv::Scalar::all(255), -1, 0, 0);
			}
		}
		
		if(hist.type() == CV_32S){
			int* ptr = hist.ptr<int>(0);
			for(int i=0;i<nBins;i++) {  
				cv::Point p0=cv::Point(i*bin_width,size.height);  
				cv::Point p1=cv::Point((i+1)*bin_width,size.height-ptr[i]*bin_unith);  
				cv::rectangle(imHist, p0, p1, cv::Scalar::all(255), -1, 0, 0);
			}
		}
		
		if(hist.type() == CV_8U){
			uchar* ptr = hist.ptr<uchar>(0);
			for(int i=0;i<nBins;i++) {  
				cv::Point p0=cv::Point(i*bin_width,size.height);  
				cv::Point p1=cv::Point((i+1)*bin_width,size.height-ptr[i]*bin_unith);  
				cv::rectangle(imHist, p0, p1, cv::Scalar::all(255), -1, 0, 0);
			} 
		}
		
		cv::namedWindow(title);
		cv::imshow(title, imHist);
	}

	void ShowImageHistogram(const std::string windowName, const cv::Mat src,
		const cv::Mat mask, int histType, cv::Size windowSize){
			CV_Assert(!src.empty());
			if (!mask.empty()){
				CV_Assert(mask.type() == CV_8U && src.size() == mask.size());
			}
			
			cv::Mat src_3u;
			if(src.channels()==1)
				cv::cvtColor(src, src_3u, CV_GRAY2RGB);
			else
				src_3u = src;
			
			//shrink the src to save time
			float th_maxSide = 300.0;
			int maxSide = cv::max(src_3u.cols , src_3u.rows);
			cv::Mat zoom_3u, zoomMask_1u;
			
			if (maxSide > th_maxSide){
				float scale = maxSide / th_maxSide;
				zoom_3u.create(src_3u.rows / scale, src_3u.cols / scale, CV_8UC3);
				cv::resize(src_3u, zoom_3u, zoom_3u.size(), 0, 0, cv::INTER_LANCZOS4 );
				
				if(!mask.empty()){
					zoomMask_1u.create(mask.rows / scale, mask.cols / scale, CV_8U);
					cv::resize(mask, zoomMask_1u, zoomMask_1u.size(), 0, 0, cv::INTER_LANCZOS4 );
				}
			}
			else{
				zoom_3u = src_3u;
				if(!mask.empty())
					zoomMask_1u = mask;
			}
			
			std::vector<cv::Mat> rgb_planes;
			cv::split(zoom_3u, rgb_planes );
			
			int nBins = 255;
			/// 设定取值范围 ( R,G,B) )
			float range[] = { 0, 256 } ;
			const float* histRange = { range };
			bool uniform = true; 
			bool accumulate = false;
			
			cv::Mat r_hist, g_hist, b_hist;
			
			/// 计算直方图:
			cv::calcHist( &rgb_planes[0], 1, 0, zoomMask_1u, r_hist, 1, &nBins, &histRange, uniform, accumulate );
			cv::calcHist( &rgb_planes[1], 1, 0, zoomMask_1u, g_hist, 1, &nBins, &histRange, uniform, accumulate );
			cv::calcHist( &rgb_planes[2], 1, 0, zoomMask_1u, b_hist, 1, &nBins, &histRange, uniform, accumulate );
			
			// 创建直方图画布
			int canvasWidth = windowSize.width; 
			int canvasHeight = windowSize.height;
			int binWidth = cvRound( (double) canvasWidth / nBins );
			cv::Mat histImage(canvasHeight, canvasWidth,  CV_8UC3, cv::Scalar( 0,0,0) );
			
			/// 将直方图归一化到范围 [ 0, histImage.rows ]
			cv::normalize(r_hist, r_hist, 0, histImage.rows, cv::NORM_MINMAX, -1, cv::Mat() );
			cv::normalize(g_hist, g_hist, 0, histImage.rows, cv::NORM_MINMAX, -1, cv::Mat() );
			cv::normalize(b_hist, b_hist, 0, histImage.rows, cv::NORM_MINMAX, -1, cv::Mat() );
			
			/// 在直方图画布上画出直方图
			if (histType == HIST_TYPE_CONTOUR){
				for( int i = 1; i < nBins; i++ ){
            cv::line( histImage, cv::Point( binWidth*(i-1), canvasHeight - cvRound(r_hist.at<float>(i-1)) ) ,
                cv::Point( binWidth*(i), canvasHeight - cvRound(r_hist.at<float>(i)) ),
                cv::Scalar(255, 0, 0), 2, 8, 0  );
            cv::line( histImage, cv::Point( binWidth*(i-1), canvasHeight - cvRound(g_hist.at<float>(i-1)) ) ,
                cv::Point( binWidth*(i), canvasHeight - cvRound(g_hist.at<float>(i)) ),
                cv::Scalar( 0, 255, 0), 2, 8, 0  );
            cv::line( histImage, cv::Point( binWidth*(i-1), canvasHeight - cvRound(b_hist.at<float>(i-1)) ) ,
                cv::Point( binWidth*(i), canvasHeight - cvRound(b_hist.at<float>(i)) ),
                cv::Scalar( 0, 0, 255), 2, 8, 0  );
				}
			}
			else if (histType == HIST_TYPE_MIX){
				for (int iBin=0; iBin<nBins; iBin++){
					for (int iValue=1; iValue < r_hist.at<float>(iBin); iValue++){
						for (int j=0; j<binWidth; j++){
							cv::Vec3b& pixel = histImage.at<cv::Vec3b>(canvasHeight - iValue, iBin * binWidth + j);
							pixel.val[0] = 255;
						}
					}
					for (int iValue=1; iValue < g_hist.at<float>(iBin); iValue++){
						for (int j=0; j<binWidth; j++){
							cv::Vec3b& pixel = histImage.at<cv::Vec3b>(canvasHeight - iValue, iBin * binWidth + j);
							pixel.val[1] = 255;
						}
					}
					
					for (int iValue=1; iValue < b_hist.at<float>(iBin); iValue++){
						for (int j=0; j<binWidth; j++){
							cv::Vec3b& pixel = histImage.at<cv::Vec3b>(canvasHeight - iValue, iBin * binWidth + j);
							pixel.val[2] = 255;
						}
					}
				}
			}
			cv::imshow(windowName, histImage );
	}
	
	bool histCompare(std::pair<cv::Scalar,int> v1, std::pair<cv::Scalar,int> v2){
			return v1.second < v2.second;
	}
	
	int countValueAppearTimes(const cv::Mat srcC1, double value){
		CV_Assert(!srcC1.empty() && srcC1.channels()==1);
		cv::Mat r = srcC1 - value;
		int times = cv::countNonZero(r);
		return srcC1.cols * srcC1.rows - times;
	}
	
	void ShowImageColorDistribution(const std::string windowName, const cv::Mat src_3u, int nBins, 
		const cv::Mat mask, cv::Size windowSize){
			CV_Assert(!src_3u.empty() );
			if (!mask.empty()){
				CV_Assert(mask.type() == CV_8U && src_3u.size() == mask.size());
			}
			
			//shrink the src to save time
			float th_maxSide = 300.0;
			int maxSide = cv::max(src_3u.cols , src_3u.rows);
			cv::Mat zoom_3u, zoomMask_1u;
			
			if (maxSide > th_maxSide){
				float scale = maxSide / th_maxSide;
				zoom_3u.create(src_3u.rows / scale, src_3u.cols / scale, CV_8UC3);
				cv::resize(src_3u, zoom_3u, zoom_3u.size(), 0, 0, cv::INTER_LANCZOS4 );
				
				if(!mask.empty()){
					zoomMask_1u.create(mask.rows / scale, mask.cols / scale, CV_8U);
					cv::resize(mask, zoomMask_1u, zoomMask_1u.size(), 0, 0, cv::INTER_LANCZOS4 );
				}
			}
			else{
				zoom_3u = src_3u;
				if(!mask.empty())
					zoomMask_1u = mask;
			}
			int maskNonZero = countNonZero(zoomMask_1u);
			
			//k-means cluster
			cv::Mat clusterMat;
			cv::Mat bestLabels, centers;
			cv::Vec3b* data = zoom_3u.ptr<cv::Vec3b>(0);
			
			if(mask.empty()){
				clusterMat.create(zoom_3u.cols * zoom_3u.rows, 3, CV_32F);
				for (int i=0; i<zoom_3u.cols * zoom_3u.rows; i++){
					cv::Vec3b pixel = data[i];
					clusterMat.at<float>(i, 0) = pixel.val[0];
					clusterMat.at<float>(i, 1) = pixel.val[1];
					clusterMat.at<float>(i, 2) = pixel.val[2];
				}
			}
			else{
				clusterMat.create(maskNonZero, 3, CV_32F);
				const uchar* maskData = zoomMask_1u.ptr<uchar>(0);
				for (int i=0, j=0; i<zoomMask_1u.cols * zoomMask_1u.rows; i++){
					if(maskData[i] > 0){
						cv::Vec3b pixel = data[i];
						clusterMat.at<float>(j, 0) = pixel.val[0];
						clusterMat.at<float>(j, 1) = pixel.val[1];
						clusterMat.at<float>(j, 2) = pixel.val[2];
						j++;
					}
				}
			}
			
			cv::kmeans(clusterMat, nBins, bestLabels, cv::TermCriteria( CV_TERMCRIT_EPS+CV_TERMCRIT_ITER, 10, 1.0),
				3, cv::KMEANS_PP_CENTERS, centers);
				
			//statistics
			std::vector<std::pair<cv::Scalar,int>> hist(nBins);
			for (int i=0; i<nBins; i++){
				cv::Scalar color( centers.at<float>(i,0), centers.at<float>(i,1), centers.at<float>(i,2));
				int val = countValueAppearTimes(bestLabels, i);
				hist.at(i) = std::pair<cv::Scalar,int>(color, val);
			}
			
			std::sort(hist.begin(), hist.end(), histCompare);
			int maxValue = hist[nBins-1].second;
			
			//canvas
			float scale = (float)windowSize.height / maxValue;
			int binWidth = windowSize.width / nBins;
			cv::Mat canvas(windowSize, CV_8UC3, cv::Scalar::all(30));
			
			for (int i=0; i<nBins; i++){
				cv::Point pt1(  i    * binWidth, canvas.rows - 1);
				cv::Point pt2( (i+1) * binWidth, canvas.rows - 1 - hist[i].second * scale);        
				cv::rectangle(canvas, pt1, pt2, hist[i].first, -1);
			}
			cv::imshow(windowName, canvas);
	}
}


关于Image Engineering & Computer Vision的更多讨论与交流,敬请关注本博和新浪微博songzi_tea.

你可能感兴趣的:(opencv,模拟Matlab显示图像)