|
2 | 2 |
|
3 | 3 | namespace cv { namespace photoeffects { |
4 | 4 |
|
5 | | -int edgeBlur(InputArray src, OutputArray dst, int indentTop, int indentLeft) |
| 5 | +class edgeBlurInvoker :public ParallelLoopBody |
| 6 | +{ |
| 7 | +public: |
| 8 | + edgeBlurInvoker(const Mat& src, |
| 9 | + const Mat& boxFilt, |
| 10 | + Mat& dst, |
| 11 | + int indentTop, |
| 12 | + int indentLeft) |
| 13 | + : src_(src), |
| 14 | + boxFilt_(boxFilt), |
| 15 | + dst_(dst), |
| 16 | + indentTop_(indentTop), |
| 17 | + indentLeft_(indentLeft) {} |
| 18 | + |
| 19 | + void operator()(const Range& range) const |
| 20 | + { |
| 21 | + float halfWidth = src_.cols / 2.0f; |
| 22 | + float halfHeight = src_.rows / 2.0f; |
| 23 | + float a = (halfWidth - indentLeft_) * (halfWidth - indentLeft_); |
| 24 | + float b = (halfHeight - indentTop_) * (halfHeight - indentTop_); |
| 25 | + |
| 26 | + Mat srcStripe = src_.rowRange(range.start, range.end); |
| 27 | + Mat boxStripe = boxFilt_.rowRange(range.start, range.end); |
| 28 | + Mat dstStripe = dst_.rowRange(range.start, range.end); |
| 29 | + |
| 30 | + int rows = srcStripe.rows; |
| 31 | + for (int i = 0; i < rows; i++) |
| 32 | + { |
| 33 | + uchar* row = (uchar*)srcStripe.row(i).data; |
| 34 | + uchar* boxRow = (uchar*)boxStripe.row(i).data; |
| 35 | + uchar* dstRow = (uchar*)dstStripe.row(i).data; |
| 36 | + float y_part = (halfHeight - (i + range.start)) * |
| 37 | + (halfHeight - (i + range.start)) / b; |
| 38 | + |
| 39 | + for (int j = 0; j < 3 * src_.cols; j += 3) |
| 40 | + { |
| 41 | + float maskEl = min(max(2.0f * |
| 42 | + ((halfWidth - j / 3) * (halfWidth - j / 3) / a + |
| 43 | + y_part - 0.5f), 0.0f), 1.0f); |
| 44 | + float negMask = 1.0f - maskEl; |
| 45 | + |
| 46 | + dstRow[j] = boxRow[j] * maskEl + row[j] * negMask; |
| 47 | + dstRow[j + 1] = boxRow[j + 1] * maskEl + row[j + 1] * negMask; |
| 48 | + dstRow[j + 2] = boxRow[j + 2] * maskEl + row[j + 2] * negMask; |
| 49 | + } |
| 50 | + } |
| 51 | + } |
| 52 | + |
| 53 | +private: |
| 54 | + const Mat& src_; |
| 55 | + const Mat& boxFilt_; |
| 56 | + Mat& dst_; |
| 57 | + int indentTop_; |
| 58 | + int indentLeft_; |
| 59 | + |
| 60 | + edgeBlurInvoker& operator=(const edgeBlurInvoker&); |
| 61 | +}; |
| 62 | + |
| 63 | +void edgeBlur(InputArray src, OutputArray dst, int indentTop, int indentLeft) |
6 | 64 | { |
7 | 65 | CV_Assert(!src.empty()); |
8 | 66 | CV_Assert(src.type() == CV_8UC3); |
| 67 | + |
9 | 68 | dst.create(src.size(), src.type()); |
10 | 69 | Mat image = src.getMat(), outputImage = dst.getMat(); |
11 | 70 |
|
12 | 71 | CV_Assert(indentTop >= 0 && indentTop <= (image.rows / 2 - 10)); |
13 | 72 | CV_Assert(indentLeft >= 0 && indentLeft <= (image.cols / 2 - 10)); |
14 | 73 |
|
15 | | - float halfWidth = image.cols / 2.0f; |
16 | | - float halfHeight = image.rows / 2.0f; |
17 | | - float a = (halfWidth - indentLeft) |
18 | | - * (halfWidth - indentLeft); |
19 | | - float b = (halfHeight - indentTop) |
20 | | - * (halfHeight - indentTop); |
21 | | - int kSizeEdges = halfWidth * halfWidth / a + halfHeight * halfHeight / b; |
22 | | - |
23 | | - // 15 is a maximal kernel size |
24 | | - kSizeEdges = MIN(kSizeEdges, 15); |
25 | | - Mat bearingImage; |
26 | | - copyMakeBorder(image, bearingImage, kSizeEdges, kSizeEdges, |
27 | | - kSizeEdges, kSizeEdges, BORDER_REPLICATE); |
| 74 | + Mat boxFilt; |
28 | 75 |
|
| 76 | + boxFilter(image, boxFilt, -1, Size(7, 7), Point(-1, -1), |
| 77 | + true, BORDER_REPLICATE); |
29 | 78 |
|
30 | | - for (int i = kSizeEdges; i < bearingImage.rows - kSizeEdges; i++) |
31 | | - { |
32 | | - for (int j = kSizeEdges; j < bearingImage.cols - kSizeEdges; j++) |
33 | | - { |
34 | | - float radius = (halfHeight - i) |
35 | | - * (halfHeight- i) |
36 | | - / b |
37 | | - + (halfWidth - j) |
38 | | - * (halfWidth - j) |
39 | | - / a; |
40 | | - if (radius < 1.0f) |
41 | | - { |
42 | | - outputImage.at<Vec3b>(i - kSizeEdges, j - kSizeEdges) = |
43 | | - bearingImage.at<Vec3b>(i, j); |
44 | | - continue; |
45 | | - } |
46 | | - int size = MIN(radius, kSizeEdges); |
47 | | - radius = 2.0f * (radius - 0.5f) * (radius - 0.5f); |
48 | | - float sumC = 0.0f; |
49 | | - Vec3f sumF; |
50 | | - float coeff1 = 1.0f / (CV_PI * radius); |
51 | | - for (int x = -size; x <= size; x++) |
52 | | - { |
53 | | - for (int y = -size; y <= size; y++) |
54 | | - { |
55 | | - float coeff2 = coeff1 * exp(- (x * x + y * y) / radius); |
56 | | - Vec3b Color = bearingImage.at<Vec3b>(x + i, y + j); |
57 | | - sumF += coeff2 * (Vec3f)Color; |
58 | | - sumC += coeff2; |
59 | | - } |
60 | | - } |
61 | | - sumF *= (1.0f / sumC); |
62 | | - outputImage.at<Vec3b>(i - kSizeEdges, |
63 | | - j - kSizeEdges) = (Vec3b)sumF; |
64 | | - } |
65 | | - } |
66 | | - |
67 | | - return 0; |
| 79 | + parallel_for_(Range(0, image.rows), |
| 80 | + edgeBlurInvoker(image, |
| 81 | + boxFilt, |
| 82 | + outputImage, |
| 83 | + indentTop, |
| 84 | + indentLeft)); |
68 | 85 | } |
69 | 86 |
|
70 | 87 | }} |
0 commit comments