OpenCV矩阵可视化工具包
在用opencv編程時,經常需要可視化地查看某個矩陣在運算過程中的狀態如何,而opencv中的imshow函數只能以灰度顯示單通道uchar或float類型的圖像,其可視化效果不盡人意,為此,我寫了一個矩陣可視化工具包,其中包含了一個類似于matlab中的imagesc的函數,能夠以不同的顏色顯示矩陣中不同大小的值,這個函數在查看矩陣時非常方便,這里貢大家參考。
VisualizationTool.h
View Code //http://www.cnblogs.com/easymind223#pragma once #ifndef _VISUALIZATION_TOOL_H_ #define _VISUALIZATION_TOOL_H_#include "opencv2/opencv.hpp"#define HIST_TYPE_MIX 0 #define HIST_TYPE_CONTOUR 1namespace VisualizationTool {//深度顯示單通道uchar,float, int類型圖像, void imageSC(std::string windowName, const cv::Mat imgC1);//以柱狀圖顯示數組,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));} #endifVisualizationTool.cpp
View Code #include "stdafx.h" #include "VisualizationTool.h"namespace VisualizationTool {void imageSC(std::string windowName, const cv::Mat imgC1) {assert(imgC1.channels() == 1 && !imgC1.empty());//get min max value of the matdouble minPixelValue, maxPixelValue;cv::minMaxIdx(imgC1, &minPixelValue, &maxPixelValue);double valueRange = maxPixelValue - minPixelValue;//init color tableconst 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 tableconst 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(imgC1.rows, tableHeight);int imageWidth = imgC1.cols + tableWidth;cv::Mat img3u( imageHeight, imageWidth, CV_8UC3, cv::Scalar::all(0));for (int i=0; i<barHeight; i++){cv::Point pt1(imgC1.cols + margin, margin + i);cv::Point pt2(imgC1.cols + margin + barWidth, margin + i);cv::line(img3u, pt1, pt2, colorTable[cvRound(i/scale)], 1);}//illustrationfor (int i=0; i<5; i++){float value = minPixelValue + i / 4.0 * valueRange;std::stringstream s;s<<value;int bx = imgC1.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(imgC1.size(), CV_32F);imgC1.convertTo(tim, CV_32F);for (int y = 0; y < imgC1.rows; y++){const float* srcData = tim.ptr<float>(y);cv::Vec3b* dstData = img3u.ptr<cv::Vec3b>(y);for (int x = 0; x<imgC1.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); }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);elsesrc_3u = src;//shrink the src to save timefloat 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 timefloat 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);//statisticsstd::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;//canvasfloat 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); }}??注意:由于博客園的bug, cpp文件中的kmeans函數會復制不全,復制以后可能會少一個參數,請仔細檢查
解釋一下文件中的幾個函數:
1. void imageSC(std::string windowName, const cv::Mat imgC1)
深度顯示單通道uchar,float, int類型圖像,類似于matlab的imagesc函數,本函數還自帶顏色表和矩陣的值域分布
例:
?
2.?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));
顯示一幅圖像的直方圖,histType為顯示方式,HIST_TYPE_MIX表示三通道混合顯示,HIST_TYPE_CONTOUR表示以輪廓顯示,窗口的寬度最好是256的倍數。
例:
?
3.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));
顯示一幅圖像的顏色分布圖,這個函數有點慢,結果也有一定的不確定性,因為用到了k-means,函數的速度取決于nBins的大小,窗口的寬度最好是256的倍數。
例:
?
?
4.?void ShowArrayHistogram(std::string title, cv::Mat array, cv::Size size = cv::Size(400,400));
以柱狀圖顯示一維數組,array必須為 CV_32F,CV_32S,CV_8U中的一種,且rows == 1,這個函數就不貼圖了~
轉載于:https://www.cnblogs.com/easymind223/archive/2013/03/31/2991866.html
總結
以上是生活随笔為你收集整理的OpenCV矩阵可视化工具包的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 第1章、从零开始学Android
- 下一篇: 购买使用vps建站(3)