图像平坦区域检测(Flat Area Detection)

使用opecv进行平坦区域检测

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
#include "opencv2/opencv.hpp"
#include <iostream>

using namespace cv;
using namespace std;

#define CLAMP(x, a, b) (MAX(a, MIN(x, b)))

void flat_gradient_cpu(Mat &src, Mat &dst, const float flatGradientThresh, bool ones = false) {
int width = src.cols;
int height = src.rows;
int one = (ones) ? 1 : 0;

float *data_src = (float *) src.data;
float *data_dst = (float *) dst.data;

for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {

int x = j;
int y = i;
int pos = y * width + x;

data_dst[pos] = 1.0f;
if (0 == x || 0 == y || (width - 1) == x || (height - 1) == y) {
continue;
}

float lrGrad = (fabs(data_src[pos + 1] - data_src[pos - 1]));
float tbGrad = (fabs(data_src[(y + 1) * width + x] - data_src[(y - 1) * width + x]));
float trblGrad = (fabs(data_src[(y - 1) * width + x + 1] - data_src[(y + 1) * width + x - 1]));
float tlbrGrad = (fabs(data_src[(y - 1) * width + x - 1] - data_src[(y + 1) * width + x + 1]));

float minGradClip = (min(tbGrad, min(trblGrad, tlbrGrad)));
float minGrad = (min(lrGrad, minGradClip));

if (minGrad > flatGradientThresh) {
float invGrad = 1.0f / (minGrad - flatGradientThresh);
data_dst[pos] = CLAMP(invGrad, 0.0f, 1.0f);
}
}
}
}

void flat_3dark_thresh(Mat &src, Mat &src2, Mat &src3, Mat &net, const float dark_thresh) {

int width = src.cols;
int height = src.rows;

float *data_src = (float *) src.data;
float *data_src2 = (float *) src2.data;
float *data_src3 = (float *) src3.data;
float *data_Net = (float *) net.data;

for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
int pos = i * width + j;

float elem1 = (1.0f - data_src[pos]);
float elem2 = (1.0f - data_src2[pos]);
float elem3 = (1.0f - data_src3[pos]);

elem1 = (elem1 + elem2 + elem3);
elem1 = 1.0f - (CLAMP(elem1, 0.0f, 1.0f));

data_src[pos] = (data_Net[pos] < dark_thresh) ? 1.0f : elem1;
}
}
}

void flat_denoise_mask(Mat &netDst, Mat &flat_mask) {

float flat_grad_thresh = 0.5;

Mat netDownX2 = Mat(netDst.size() / 2, netDst.type());
Mat maskDownX2 = Mat(flat_mask.size() / 2, flat_mask.type());
Mat netDownX4 = Mat(netDownX2.size() / 2, netDownX2.type());
Mat maskDownX4 = Mat(maskDownX2.size() / 2, maskDownX2.type());

Mat flatMaskUpBy2 = Mat(flat_mask.size(), flat_mask.type());
Mat flatMaskUpBy4 = Mat(flat_mask.size(), flat_mask.type());

flat_gradient_cpu(netDst, flat_mask, flat_grad_thresh, true);
resize(netDst, netDownX2, netDownX2.size(), 0, 0, INTER_NEAREST);
flat_gradient_cpu(netDownX2, maskDownX2, flat_grad_thresh, true);
resize(netDownX2, netDownX4, netDownX4.size(), 0, 0, INTER_NEAREST);
flat_gradient_cpu(netDownX4, maskDownX4, flat_grad_thresh, true);
resize(maskDownX2, flatMaskUpBy2, flatMaskUpBy2.size(), 0, 0, INTER_NEAREST);
resize(maskDownX4, flatMaskUpBy4, flatMaskUpBy4.size(), 0, 0, INTER_NEAREST);
flat_3dark_thresh(flat_mask, flatMaskUpBy2, flatMaskUpBy4, netDst, flat_grad_thresh);
}

int main() {
Mat img = imread("/Users/huziliang/Documents/C++/funny/flat_area.png", IMREAD_GRAYSCALE);
Mat img_f, dst_f;
img.convertTo(img_f, CV_32FC1);
boxFilter(img_f, img_f, -1, Size(3, 3));
dst_f = Mat::zeros(img_f.size(), img_f.type());
flat_denoise_mask(img_f, dst_f);
imwrite("/Users/huziliang/Documents/C++/funny/flat_area_result.png", dst_f * 255.0f);
}