1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
#include "histogram.hpp"
#include <QHBoxLayout>
#include <iostream>
#include "util.hpp"
namespace cvv
{
namespace qtutil
{
Histogram::Histogram(const cv::Mat& mat, QWidget* parent)
:QWidget{parent},
histSize_(512, 200),
histLineWidth_(2),
histBackgroundColor_(255, 255, 255)
{
setMat(mat);
zoomableImage = new ZoomableImage();
auto layout = new QHBoxLayout();
layout->addWidget(zoomableImage);
setLayout(layout);
}
void Histogram::setMat(const cv::Mat& mat)
{
mat_ = mat;
}
cv::Rect Histogram::qrect2cvrect(const cv::Mat& mat, QRectF qrect)
{
double x1, y1, x2, y2;
qrect.getCoords(&x1, &y1, &x2, &y2);
x1 = std::max(0.0, x1);
y1 = std::max(0.0, y1);
x2 = std::min(static_cast<double>(mat.size().width), x2);
y2 = std::min(static_cast<double>(mat.size().height), y2);
double width = x2 - x1;
double height = y2 - y1;
return cv::Rect(x1, y1, width, height);
}
void Histogram::setArea(QRectF rect, qreal zoom)
{
(void)zoom;
channelHists_ = calcHist(mat_, qrect2cvrect(mat_, rect));
histMat_ = drawHist(channelHists_, histSize_, histLineWidth_, histBackgroundColor_);
zoomableImage->setMat(histMat_);
zoomableImage->showFullImage();
}
std::vector<cv::Mat> Histogram::calcHist(cv::Mat mat, cv::Rect rect, int bins, float rangeMin,
float rangeMax)
{
cv::Mat rectMat(mat, rect);
cv::Mat histMat;
std::vector<cv::Mat> channelPlanes = splitChannels(rectMat);
int histSize = bins;
float range[] = {rangeMin, rangeMax};
const float* histRange = {range};
bool uniform = true;
bool accumulate = false;
std::vector<cv::Mat> channelHists(channelPlanes.size());
for (size_t chan = 0; chan < channelPlanes.size(); chan++)
{
cv::calcHist(&channelPlanes[chan], 1, 0, cv::Mat(), channelHists[chan], 1, &histSize,
&histRange, uniform, accumulate);
}
return channelHists;
}
cv::Mat Histogram::drawHist(const std::vector<cv::Mat>& channelHists, cv::Size histSize,
int lineWidth, const cv::Scalar& backgroundColor)
{
int binCount = channelHists[0].rows;
int binWidth = cvRound(double(histSize.width)/binCount);
std::vector<cv::Scalar> colors{cv::Scalar(255, 0, 0), cv::Scalar(0, 255, 0),
cv::Scalar(0, 0, 255), cv::Scalar(0, 0, 0)}; // BGR
cv::Mat histMat(histSize, CV_8UC3, backgroundColor);
double maxVal = 0;
for (auto& hist : channelHists)
{
double tmpMaxVal;
cv::minMaxLoc(hist, NULL, &tmpMaxVal);
maxVal = std::max(maxVal, tmpMaxVal);
}
double valScale = histSize.height / maxVal;
for (size_t channel = 0; channel < channelHists.size(); channel++)
{
auto& hist = channelHists[channel];
auto& color = colors[channel];
for (int bin = 1; bin < binCount; bin++)
{
//printf("%zd:%d=%f\n", channel, bin, hist.at<float>(bin));
auto pt1 = cv::Point(binWidth * (bin-1),
histSize.height - cvRound(hist.at<float>(bin-1) * valScale));
auto pt2 = cv::Point(binWidth * bin,
histSize.height - cvRound(hist.at<float>(bin) * valScale));
cv::line(histMat, pt1, pt2, color, lineWidth);
}
}
int binTextStep = binCount / 5;
binTextStep = binTextStep - (binTextStep % 10); // round to tens
int fontFace = cv::FONT_HERSHEY_SCRIPT_SIMPLEX;
double fontScale = 0.5;
auto textColor = cv::Scalar::all(0);
int thickness = 1;
for (int binTextId = 0; binTextId < binCount; binTextId += binTextStep)
{
auto text = QString::number(binTextId).toLatin1();
auto textSize = cv::getTextSize(text.data(), fontFace, fontScale, thickness, NULL);
auto textPt = cv::Point(std::max(0, binWidth * binTextId - textSize.width/2), histSize.height);
cv::putText(histMat, text.data(), textPt, fontFace, fontScale, textColor, thickness);
auto linePt1 = cv::Point(binWidth * binTextId, 0);
auto linePt2 = cv::Point(binWidth * binTextId, histSize.height - textSize.height);
cv::line(histMat, linePt1, linePt2, textColor);
}
return histMat;
}
}
}