Skip to content

Commit 22139f7

Browse files
committed
[feat] add FlatFieldCorrection()
1 parent 79541ff commit 22139f7

File tree

8 files changed

+222
-3
lines changed

8 files changed

+222
-3
lines changed
12.1 KB
Loading

images/flat-field-correction/dark.jpg

5.86 KB
Loading
37.4 KB
Loading
35.3 KB
Loading

include/component/correction.h

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#ifndef _CORRECTION_H_
2+
#define _CORRECTION_H_
3+
#include "common.h"
4+
#include "image_proc.h"
5+
namespace ipo {
6+
class FlatFieldCorrection::PimplFlatFieldCorrection {
7+
public:
8+
PimplFlatFieldCorrection();
9+
~PimplFlatFieldCorrection();
10+
int SetDarkAndBrightFieldImage(const cv::Mat &dark_field_img,
11+
const cv::Mat &bright_field_img,
12+
const int &mean_pixel_value);
13+
cv::Mat GetResult(const cv::Mat &src);
14+
15+
private:
16+
int mean_pixel_value = 128; //default
17+
int img_channel;
18+
cv::Mat gain;
19+
cv::Mat dark_field_img;
20+
};
21+
} // namespace ipo
22+
#endif // _CORRECTION_H_

include/component/image_proc.h

+15
Original file line numberDiff line numberDiff line change
@@ -60,5 +60,20 @@ class Positioning {
6060
std::auto_ptr<PimplPositioning> p_pimplPositioning;
6161
};
6262

63+
//====Flat-field correction====
64+
class FlatFieldCorrection {
65+
public:
66+
FlatFieldCorrection();
67+
~FlatFieldCorrection();
68+
int SetDarkAndBrightFieldImage(const cv::Mat &dark_field_img,
69+
const cv::Mat &bright_field_img,
70+
const int &mean_pixel_value);
71+
cv::Mat GetResult(const cv::Mat &src);
72+
73+
private:
74+
class PimplFlatFieldCorrection;
75+
std::auto_ptr<PimplFlatFieldCorrection> p_pimplFlatFieldCorrection;
76+
};
77+
6378
} // namespace ipo
6479
#endif // _IMAGE_PROC_H_

main.cpp

+21-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
#include "component/image_proc.h"
1+
#include <iostream>
22

3+
#include "component/image_proc.h"
34
// ---load image---
45
cv::Mat &&src = cv::imread("../images/Okonomiyaki.png");
56
/*
@@ -15,9 +16,10 @@ cv::Mat &&src = cv::imread("../images/Okonomiyaki.png");
1516
------positioning------
1617
8 : positioning by feature matching(SURF)
1718
9 : positioning by template matching
18-
10 :
19+
------Flate-Field-Correction------
20+
10 : FlatFieldCorrection
1921
*/
20-
#define index 9
22+
#define index 10
2123

2224
#if index == 1
2325
// DynamicThreshold
@@ -158,5 +160,21 @@ int main() {
158160
}
159161
#elif index == 10
160162
int main() {
163+
// image from : https://rawpedia.rawtherapee.com/File:Flatfield_landscape.jpg#file
164+
//----Load images----
165+
cv::Mat &&dark_field = cv::imread("../images/flat-field-correction/dark.jpg");
166+
cv::Mat &&bright_field = cv::imread("../images/flat-field-correction/bright.jpg");
167+
cv::Mat &&sample = cv::imread("../images/flat-field-correction/sample.jpg");
168+
169+
std::shared_ptr<ipo::FlatFieldCorrection> &&obj = std::make_shared<ipo::FlatFieldCorrection>();
170+
if (obj->SetDarkAndBrightFieldImage(dark_field, bright_field, 200) != 0)
171+
return -1;
172+
cv::Mat &&dst = obj->GetResult(sample);
173+
if (dst.empty()) {
174+
return -1;
175+
}
176+
cv::imshow("dst", dst);
177+
cv::waitKey(0);
178+
return 0;
161179
}
162180
#endif

src/component/correction.cpp

+164
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
#include "correction.h"
2+
3+
#include "image_proc.h"
4+
using namespace ipo;
5+
//===========PIMPL (FlatFieldCorrection)===========
6+
FlatFieldCorrection::FlatFieldCorrection() : p_pimplFlatFieldCorrection(new PimplFlatFieldCorrection) {}
7+
FlatFieldCorrection::~FlatFieldCorrection() {}
8+
int FlatFieldCorrection::SetDarkAndBrightFieldImage(const cv::Mat &dark_field_img,
9+
const cv::Mat &bright_field_img,
10+
const int &mean_pixel_value) {
11+
return p_pimplFlatFieldCorrection->SetDarkAndBrightFieldImage(dark_field_img, bright_field_img, mean_pixel_value);
12+
}
13+
14+
cv::Mat FlatFieldCorrection::GetResult(const cv::Mat &src) {
15+
return p_pimplFlatFieldCorrection->GetResult(src);
16+
}
17+
//===========
18+
19+
FlatFieldCorrection::PimplFlatFieldCorrection::PimplFlatFieldCorrection() {}
20+
FlatFieldCorrection::PimplFlatFieldCorrection::~PimplFlatFieldCorrection() {}
21+
int FlatFieldCorrection::PimplFlatFieldCorrection::SetDarkAndBrightFieldImage(const cv::Mat &dark_field_img,
22+
const cv::Mat &bright_field_img,
23+
const int &mean_pixel_value) {
24+
// check input
25+
if (dark_field_img.empty()) {
26+
std::cout << "\nERROR: int ipo::FlatFieldCorrection::SetDarkAndBrightFieldImage --(cv::Mat)dark_field_img.empty()" << std::endl;
27+
return -1;
28+
} else if (bright_field_img.empty()) {
29+
std::cout << "\nERROR: int ipo::FlatFieldCorrection::SetDarkAndBrightFieldImage --(cv::Mat)bright_field_img.empty()" << std::endl;
30+
return -1;
31+
} else if (dark_field_img.channels() != bright_field_img.channels()) {
32+
std::cout << "\nERROR: ipo::FlatFieldCorrection::SetDarkAndBrightFieldImage" << std::endl;
33+
std::cout << " --the number of channel between (cv::Mat)dark_field_img && (cv::Mat)bright_field_img channels() are different" << std::endl;
34+
return -1;
35+
}
36+
37+
// print parameter
38+
if (mean_pixel_value < 0)
39+
this->mean_pixel_value = 0;
40+
else if (mean_pixel_value > 255)
41+
this->mean_pixel_value = 255;
42+
else
43+
this->mean_pixel_value = mean_pixel_value;
44+
std::cout << "userset : this->mean_pixel_value = " << this->mean_pixel_value << std::endl;
45+
46+
// clone image
47+
this->dark_field_img = cv::Mat::zeros(dark_field_img.size(), dark_field_img.type());
48+
this->dark_field_img = dark_field_img.clone();
49+
cv::Mat &&bright_img = cv::Mat::zeros(bright_field_img.size(), bright_field_img.type());
50+
bright_img = bright_field_img.clone();
51+
52+
// according to the channel to process separately
53+
const int channel = this->dark_field_img.channels();
54+
this->img_channel = channel;
55+
const int &width = dark_field_img.cols;
56+
const int &height = dark_field_img.rows;
57+
switch (channel) {
58+
case 1: {
59+
// allocate memory for gain matrix
60+
this->gain = cv::Mat::zeros(dark_field_img.size(), CV_64FC1);
61+
// m
62+
// const double &mean_value = cv::mean(bright_field_img - dark_field_img)[0];
63+
for (size_t j = 0; j < height; j++) {
64+
uchar *p_dark = this->dark_field_img.ptr<uchar>(j);
65+
uchar *p_bright = bright_img.ptr<uchar>(j);
66+
double *p_gain = this->gain.ptr<double>(j);
67+
for (size_t i = 0; i < width; i++) {
68+
p_gain[i] = static_cast<double>(this->mean_pixel_value / static_cast<double>(p_bright[i] - p_dark[i]));
69+
}
70+
}
71+
break;
72+
}
73+
case 3: {
74+
// allocate memory for gain matrix
75+
this->gain = cv::Mat::zeros(dark_field_img.size(), CV_64FC3);
76+
for (size_t j = 0; j < height; j++) {
77+
cv::Vec3b *p_dark = this->dark_field_img.ptr<cv::Vec3b>(j);
78+
cv::Vec3b *p_bright = bright_img.ptr<cv::Vec3b>(j);
79+
cv::Vec3d *p_gain = this->gain.ptr<cv::Vec3d>(j);
80+
for (size_t i = 0; i < width; i++) {
81+
for (size_t k = 0; k < 3; k++) {
82+
p_gain[i][k] = static_cast<double>(this->mean_pixel_value / static_cast<double>(p_bright[i][k] - p_dark[i][k]));
83+
}
84+
}
85+
}
86+
break;
87+
}
88+
default: {
89+
std::cout << "\nERROR: ipo::FlatFieldCorrection::SetDarkAndBrightFieldImage" << std::endl;
90+
std::cout << " --(cv::Mat)channel must be equal to 1 || 3" << std::endl;
91+
return -1;
92+
}
93+
}
94+
return 0;
95+
}
96+
97+
cv::Mat FlatFieldCorrection::PimplFlatFieldCorrection::GetResult(const cv::Mat &src) {
98+
// check input
99+
if (src.empty()) {
100+
std::cout << "\nERROR: cv::Mat ipo::FlatFieldCorrection::GetResult" << std::endl;
101+
std::cout << " --(cv::Mat)src.empty()" << std::endl;
102+
return {};
103+
} else if (this->img_channel != src.channels()) {
104+
std::cout << "\nERROR: cv::Mat ipo::FlatFieldCorrection::GetResult" << std::endl;
105+
std::cout << " --(cv::Mat)the channel is different" << std::endl;
106+
return {};
107+
} else if (this->gain.empty()) {
108+
std::cout << "\nERROR: cv::Mat ipo::FlatFieldCorrection::GetResult" << std::endl;
109+
std::cout << " --(cv::Mat)this->gain.empty()" << std::endl;
110+
return {};
111+
}
112+
113+
// clone image
114+
cv::Mat &&sample = cv::Mat::zeros(src.size(), src.type());
115+
sample = src.clone();
116+
117+
cv::Mat &&dst = cv::Mat::zeros(src.size(), src.type());
118+
119+
const int &width = src.cols;
120+
const int &height = src.rows;
121+
switch (this->img_channel) {
122+
case 1: {
123+
for (int j = 0; j < height; j++) {
124+
uchar *R = sample.ptr<uchar>(j);
125+
uchar *D = this->dark_field_img.ptr<uchar>(j);
126+
double *G = this->gain.ptr<double>(j);
127+
uchar *p_dst = dst.ptr<uchar>(j);
128+
for (int i = 0; i < width; i++) {
129+
double &&value = static_cast<double>(static_cast<double>(R[i] - D[i]) * G[i]);
130+
if (value < 0)
131+
value = 0;
132+
else if (value > 255)
133+
value = 255;
134+
p_dst[i] = static_cast<uchar>(value);
135+
}
136+
}
137+
break;
138+
}
139+
case 3: {
140+
for (int j = 0; j < height; j++) {
141+
cv::Vec3b *R = sample.ptr<cv::Vec3b>(j);
142+
cv::Vec3b *D = this->dark_field_img.ptr<cv::Vec3b>(j);
143+
cv::Vec3d *G = this->gain.ptr<cv::Vec3d>(j);
144+
cv::Vec3b *p_dst = dst.ptr<cv::Vec3b>(j);
145+
for (int i = 0; i < width; i++) {
146+
for (int k = 0; k < 3; k++) {
147+
double &&value = static_cast<double>(static_cast<double>(R[i][k] - D[i][k]) * G[i][k]);
148+
if (value < 0)
149+
value = 0;
150+
else if (value > 255)
151+
value = 255;
152+
p_dst[i][k] = static_cast<uchar>(value);
153+
}
154+
}
155+
}
156+
break;
157+
}
158+
default: {
159+
std::cout << "\nERROR: cv::Mat ipo::FlatFieldCorrection::GetResult" << std::endl;
160+
return {};
161+
}
162+
}
163+
return dst.clone();
164+
}

0 commit comments

Comments
 (0)