-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathImageProcessor.cpp
More file actions
350 lines (297 loc) · 10.5 KB
/
Copy pathImageProcessor.cpp
File metadata and controls
350 lines (297 loc) · 10.5 KB
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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
#include "ImageProcessor.h"
#include <iostream>
using namespace std;
// Fonction pour ajouter un filtre au gestionnaire de filtres
void ImageProcessor::addFilter(const std::string &name, FilterFunction filter)
{
filters[name] = filter;
}
// Fonctoion pour ppliquer un filtre par nom
cv::Mat ImageProcessor::applyFilter(const std::string &name, const cv::Mat &src)
{
if (filters.find(name) != filters.end())
{
return filters[name](src);
}
else
{
std::cerr << "Filter not found: " << name << std::endl;
return src.clone();
}
}
/****************************************************************************************
* TRAITEMENTS & HISTOGRAMMES *
****************************************************************************************/
// Calculer un histogramme de couleurs
cv::Mat ImageProcessor::calculateHistogram(const cv::Mat &src)
{
std::vector<int> histogram(256, 0);
for (int y = 0; y < src.rows; ++y)
{
for (int x = 0; x < src.cols; ++x)
{
int pixelValue = src.at<uchar>(y, x);
histogram[pixelValue]++;
}
}
cv::Mat histImage(256, 256, CV_8U, cv::Scalar(255));
int max = *std::max_element(histogram.begin(), histogram.end());
for (int i = 0; i < 256; ++i)
{
int value = static_cast<int>(histogram[i] * 256 / max);
cv::line(histImage, cv::Point(i, 256), cv::Point(i, 256 - value), cv::Scalar(0));
}
return histImage;
}
// Calculer un histogramme cumulé
cv::Mat ImageProcessor::calculateCumulatedHistogram(const cv::Mat &src)
{
std::vector<int> histogram(256, 0);
std::vector<int> cumulativeHistogram(256, 0);
for (int y = 0; y < src.rows; ++y)
{
for (int x = 0; x < src.cols; ++x)
{
int pixelValue = src.at<uchar>(y, x);
histogram[pixelValue]++;
}
}
cumulativeHistogram[0] = histogram[0];
for (int i = 1; i < 256; ++i)
{
cumulativeHistogram[i] = cumulativeHistogram[i - 1] + histogram[i];
}
cv::Mat histImage(256, 256, CV_8U, cv::Scalar(255));
int max = *std::max_element(cumulativeHistogram.begin(), cumulativeHistogram.end());
for (int i = 0; i < 256; ++i)
{
int value = static_cast<int>(cumulativeHistogram[i] * 256 / max);
cv::line(histImage, cv::Point(i, 256), cv::Point(i, 256 - value), cv::Scalar(0));
}
return histImage;
}
// Égalisation d'histogramme
cv::Mat ImageProcessor::equalizeHistogram(const cv::Mat &src){
CV_Assert(src.type() == CV_8UC3); // Vérification : image en couleur
// Convertir l'image en espace YCrCb
cv::Mat ycrcb;
cv::cvtColor(src, ycrcb, cv::COLOR_BGR2YCrCb);
// Diviser les canaux
std::vector<cv::Mat> channels;
cv::split(ycrcb, channels);
// Calcul de l'histogramme pour le canal Y
std::vector<int> histogram(256, 0);
for (int y = 0; y < channels[0].rows; ++y)
{
for (int x = 0; x < channels[0].cols; ++x)
{
int pixelValue = channels[0].at<uchar>(y, x);
histogram[pixelValue]++;
}
}
// Calcul de la distribution de probabilité P(y)
int totalPixels = channels[0].rows * channels[0].cols;
std::vector<double> probability(256, 0.0);
for (int i = 0; i < 256; ++i)
{
probability[i] = static_cast<double>(histogram[i]) / totalPixels;
}
// Calcul de la CDF
std::vector<double> cdf(256, 0.0);
cdf[0] = probability[0];
for (int i = 1; i < 256; ++i)
{
cdf[i] = cdf[i - 1] + probability[i];
}
// Mise à jour des valeurs d'intensité lumineuse
std::vector<uchar> lut(256, 0);
double cdfMin = cdf[0];
for (int i = 0; i < 256; ++i)
{
lut[i] = static_cast<uchar>((cdf[i] - cdfMin) * 255 / (1.0 - cdfMin));
}
// Appliquer la LUT au canal Y
for (int y = 0; y < channels[0].rows; ++y)
{
for (int x = 0; x < channels[0].cols; ++x)
{
channels[0].at<uchar>(y, x) = lut[channels[0].at<uchar>(y, x)];
}
}
// Fusionner les canaux
cv::Mat equalizedYCrCb;
cv::merge(channels, equalizedYCrCb);
// Reconvertir en espace BGR
cv::Mat equalizedImage;
cv::cvtColor(equalizedYCrCb, equalizedImage, cv::COLOR_YCrCb2BGR);
return equalizedImage;
}
// Étirement d'histogramme
cv::Mat ImageProcessor::stretchHistogram(const cv::Mat &src) {
CV_Assert(src.type() == CV_8UC3); // Ensure the image is a color image (BGR)
// Split the image into its three channels (Blue, Green, Red)
std::vector<cv::Mat> channels(3);
cv::split(src, channels);
// Process each channel independently
for (int i = 0; i < 3; ++i)
{
// Find the minimum and maximum pixel values in the current channel
double minVal, maxVal;
cv::minMaxLoc(channels[i], &minVal, &maxVal);
// Apply the histogram stretching on the current channel
for (int y = 0; y < channels[i].rows; ++y)
{
for (int x = 0; x < channels[i].cols; ++x)
{
// Retrieve the pixel value and stretch it to the [0, 255] range
uchar pixelValue = channels[i].at<uchar>(y, x);
int stretchedValue = static_cast<int>((pixelValue - minVal) * 255 / (maxVal - minVal));
channels[i].at<uchar>(y, x) = static_cast<uchar>(stretchedValue);
}
}
}
// Merge the channels back to a single image
cv::Mat stretchedImage;
cv::merge(channels, stretchedImage);
return stretchedImage;
}
/****************************************************************************************
* OPERATIONS DE TRANSFORMATION GÉOMÉTRIQUE D'IMAGES *
****************************************************************************************/
// Zoom (agrandissement)
cv::Mat ImageProcessor::zoom(const cv::Mat &src, double scaleFactor)
{
int newRows = src.rows;
int newCols = src.cols;
cv::Mat dst(newRows, newCols, src.type());
for (int y = 0; y < newRows; ++y)
{
for (int x = 0; x < newCols; ++x)
{
int srcY = static_cast<int>((y - newRows / 2) / scaleFactor + newRows / 2);
int srcX = static_cast<int>((x - newCols / 2) / scaleFactor + newCols / 2);
if (srcY >= 0 && srcY < src.rows && srcX >= 0 && srcX < src.cols)
{
// Remplir avec les valeurs de l'image source si dans les limites
dst.at<cv::Vec3b>(y, x) = src.at<cv::Vec3b>(srcY, srcX);
}
else
{
// Remplir avec du noir si hors limites
dst.at<cv::Vec3b>(y, x) = cv::Vec3b(0, 0, 0);
}
}
}
return dst;
}
// Réduction
cv::Mat ImageProcessor::reduce(const cv::Mat &src, double scaleFactor)
{
// Vérifier que le facteur de réduction est valide
if (scaleFactor <= 0 || scaleFactor >= 1)
{
std::cerr << "Scale factor doit être compris entre 0 et 1" << std::endl;
return src;
}
return zoom(src, scaleFactor);
}
// Compression
cv::Mat ImageProcessor::compress(const cv::Mat &src){
CV_Assert(src.type() == CV_8UC3); // Vérification : image en couleur
// Diviser l'image en ses trois canaux (Bleu, Vert, Rouge)
std::vector<cv::Mat> channels(3);
cv::split(src, channels);
// Processus de chaque canal indépendamment
for (int i = 0; i < 3; ++i)
{
// Trouver les valeurs minimale et maximale des pixels dans le canal actuel
double minVal = 255, maxVal = 0;
for (int y = 0; y < channels[i].rows; ++y)
{
for (int x = 0; x < channels[i].cols; ++x)
{
uchar pixelValue = channels[i].at<uchar>(y, x);
if (pixelValue < minVal) minVal = pixelValue;
if (pixelValue > maxVal) maxVal = pixelValue;
}
}
// Appliquer la compression d'histogramme sur le canal actuel
for (int y = 0; y < channels[i].rows; ++y)
{
for (int x = 0; x < channels[i].cols; ++x)
{
uchar pixelValue = channels[i].at<uchar>(y, x);
int stretchedValue = static_cast<int>((pixelValue - minVal) * 255 / (maxVal - minVal));
channels[i].at<uchar>(y, x) = static_cast<uchar>(stretchedValue);
}
}
}
// Fusionner les canaux en une seule image
cv::Mat compressedImage;
cv::merge(channels, compressedImage);
return compressedImage;
}
// Rotation
cv::Mat ImageProcessor::rotate(const cv::Mat &src, double angle){
int rows = src.rows;
int cols = src.cols;
cv::Mat dst(rows, cols, src.type());
// convertir l'angle en radians
double radians = angle * CV_PI / 180.0;
double cosA = cos(radians);
double sinA = sin(radians);
int centerX = cols / 2;
int centerY = rows / 2;
// Appliquer la rotation
for (int y = 0; y < rows; ++y)
{
for (int x = 0; x < cols; ++x)
{
int newX = static_cast<int>((x - centerX) * cosA - (y - centerY) * sinA + centerX);
int newY = static_cast<int>((x - centerX) * sinA + (y - centerY) * cosA + centerY);
if (newX >= 0 && newX < cols && newY >= 0 && newY < rows)
{
// Remplir avec les valeurs de l'image source si dans les limites
dst.at<cv::Vec3b>(y, x) = src.at<cv::Vec3b>(newY, newX);
}
else
{
// Remplir avec du noir si hors limites
dst.at<cv::Vec3b>(y, x) = cv::Vec3b(0, 0, 0);
}
}
}
return dst;
}
// Flip
cv::Mat ImageProcessor::flip(const cv::Mat &src, int flipCode)
{
int rows = src.rows;
int cols = src.cols;
cv::Mat dst(rows, cols, src.type());
// Appliquer le flip
for (int y = 0; y < rows; ++y)
{
for (int x = 0; x < cols; ++x)
{
int newX = x;
int newY = y;
if (flipCode == 0) // Vertical flip
{
newY = rows - y - 1;
}
else if (flipCode == 1) // Horizontal flip
{
newX = cols - x - 1;
}
else if (flipCode == -1) // flip horizontal et vertical
{
newX = cols - x - 1;
newY = rows - y - 1;
}
// Remplir avec les valeurs de l'image source
dst.at<cv::Vec3b>(y, x) = src.at<cv::Vec3b>(newY, newX);
}
}
return dst;
}