【发布时间】:2022-06-11 13:37:15
【问题描述】:
我有一个填孔过滤器的基本实现,如下所示:
#include <iostream>
#include <opencv2/opencv.hpp>
int main(int argc, char** argv)
{
// please note that the depthImg is (720 x 576) 8UC1
// let's make a smaller one for testing
uchar flatten[6 * 8] = { 140, 185, 48, 235, 201, 192, 131, 57,
55, 87, 82, 0, 6, 201, 0, 38,
6, 239, 82, 142, 46, 33, 172, 72,
133, 0, 232, 226, 66, 59, 10, 204,
214, 123, 202, 100, 0, 32, 6, 147,
105, 191, 50, 21, 87, 117, 118, 244};
cv::Mat depthImg = cv::Mat(6, 8, CV_8UC1, flatten);
// please ignore the border pixels in this case
for (int i = 1; i < depthImg.cols - 1; i++) {
for (int j = 1; j < depthImg.rows - 1; j++) {
unsigned short sumNonZeroAdjs = 0;
uchar countNonZeroAdjs = 0;
if (depthImg.at<uchar>(j, i) == 0) {
uchar iMinus1 = depthImg.at<uchar>(j, i - 1);
uchar iPlus1 = depthImg.at<uchar>(j, i + 1);
uchar jMinus1 = depthImg.at<uchar>(j - 1, i);
uchar jPlus1 = depthImg.at<uchar>(j + 1, i);
if (iMinus1 != 0) {
sumNonZeroAdjs += iMinus1;
countNonZeroAdjs++;
}
if (iPlus1 != 0) {
sumNonZeroAdjs += iPlus1;
countNonZeroAdjs++;
}
if (jMinus1 != 0) {
sumNonZeroAdjs += jMinus1;
countNonZeroAdjs++;
}
if (jPlus1 != 0) {
sumNonZeroAdjs += jPlus1;
countNonZeroAdjs++;
}
depthImg.at<uchar>(j, i) = sumNonZeroAdjs / countNonZeroAdjs;
}
}
}
std::cout << depthImg << std::endl;
return 0;
}
// prints the following:
[140, 185, 48, 235, 201, 192, 131, 57;
55, 87, 82, 116, 6, 201, 135, 38;
6, 239, 82, 142, 46, 33, 172, 72;
133, 181, 232, 226, 66, 59, 10, 204;
214, 123, 202, 100, 71, 32, 6, 147;
105, 191, 50, 21, 87, 117, 118, 244]
上述过滤器计算相邻像素的平均值以填充 0 像素。这个实现的输出是令人满意的。然而,正如我们所见,上面的原型并不优雅,而且速度慢得令人痛苦。
我正在寻找类似的逻辑(使用相邻像素填充 0 像素)但更快(执行时间)OpenCV 中内置的孔填充过滤器
PS:我在 Ubuntu 20.04 LTS 上使用 OpenCV v4.2.0。
更新 1
根据建议,我设计了指针样式访问。完整代码如下:
#include <iostream>
#include <opencv2/opencv.hpp>
void inPlaceHoleFillingExceptBorderPtrStyle(cv::Mat& img) {
typedef uchar T;
T* ptr = img.data;
size_t elemStep = img.step / sizeof(T);
for (int i = 1; i < img.rows - 1; i++) {
for (int j = 1; j < img.cols - 1; j++) {
T& curr = ptr[i * elemStep + j];
if (curr != 0) {
continue;
}
ushort sumNonZeroAdjs = 0;
uchar countNonZeroAdjs = 0;
T iM1 = ptr[(i - 1) * elemStep + j];
T iP1 = ptr[(i + 1) * elemStep + j];
T jM1 = ptr[i * elemStep + (j - 1)];
T jP1 = ptr[i * elemStep + (j + 1)];
if (iM1 != 0) {
sumNonZeroAdjs += iM1;
countNonZeroAdjs++;
}
if (iP1 != 0) {
sumNonZeroAdjs += iP1;
countNonZeroAdjs++;
}
if (jM1 != 0) {
sumNonZeroAdjs += jM1;
countNonZeroAdjs++;
}
if (jP1 != 0) {
sumNonZeroAdjs += jP1;
countNonZeroAdjs++;
}
if (countNonZeroAdjs > 0) {
curr = sumNonZeroAdjs / countNonZeroAdjs;
}
}
}
}
void inPlaceHoleFillingExceptBorder(cv::Mat& img) {
typedef uchar T;
for (int i = 1; i < img.cols - 1; i++) {
for (int j = 1; j < img.rows - 1; j++) {
ushort sumNonZeroAdjs = 0;
uchar countNonZeroAdjs = 0;
if (img.at<T>(j, i) != 0) {
continue;
}
T iM1 = img.at<T>(j, i - 1);
T iP1 = img.at<T>(j, i + 1);
T jM1 = img.at<T>(j - 1, i);
T jP1 = img.at<T>(j + 1, i);
if (iM1 != 0) {
sumNonZeroAdjs += iM1;
countNonZeroAdjs++;
}
if (iP1 != 0) {
sumNonZeroAdjs += iP1;
countNonZeroAdjs++;
}
if (jM1 != 0) {
sumNonZeroAdjs += jM1;
countNonZeroAdjs++;
}
if (jP1 != 0) {
sumNonZeroAdjs += jP1;
countNonZeroAdjs++;
}
if (countNonZeroAdjs > 0) {
img.at<T>(j, i) = sumNonZeroAdjs / countNonZeroAdjs;
}
}
}
}
int main(int argc, char** argv) {
// please note that the img is (720 x 576) 8UC1
// let's make a smaller one for testing
// clang-format off
uchar flatten[6 * 8] = { 140, 185, 48, 235, 201, 192, 131, 57,
55, 87, 82, 0, 6, 201, 0, 38,
6, 239, 82, 142, 46, 33, 172, 72,
133, 0, 232, 226, 66, 59, 10, 204,
214, 123, 202, 100, 0, 32, 6, 147,
105, 191, 50, 21, 87, 117, 118, 244};
// clang-format on
cv::Mat img = cv::Mat(6, 8, CV_8UC1, flatten);
cv::Mat img1 = img.clone();
cv::Mat img2 = img.clone();
inPlaceHoleFillingExceptBorderPtrStyle(img1);
inPlaceHoleFillingExceptBorder(img2);
return 0;
}
/*** expected output
[140, 185, 48, 235, 201, 192, 131, 57;
55, 87, 82, 116, 6, 201, 135, 38;
6, 239, 82, 142, 46, 33, 172, 72;
133, 181, 232, 226, 66, 59, 10, 204;
214, 123, 202, 100, 71, 32, 6, 147;
105, 191, 50, 21, 87, 117, 118, 244]
***/
更新 2
根据建议,点样式代码进一步改进如下:
void inPlaceHoleFillingExceptBorderImpv(cv::Mat& img) {
typedef uchar T;
size_t elemStep = img.step1();
const size_t margin = 1;
for (size_t i = margin; i < img.rows - margin; ++i) {
T* ptr = img.data + i * elemStep;
for (size_t j = margin; j < img.cols - margin; ++j, ++ptr) {
T& curr = ptr[margin];
if (curr != 0) {
continue;
}
T& north = ptr[margin - elemStep];
T& south = ptr[margin + elemStep];
T& east = ptr[margin + 1];
T& west = ptr[margin - 1];
ushort sumNonZeroAdjs = 0;
uchar countNonZeroAdjs = 0;
if (north != 0) {
sumNonZeroAdjs += north;
countNonZeroAdjs++;
}
if (south != 0) {
sumNonZeroAdjs += south;
countNonZeroAdjs++;
}
if (east != 0) {
sumNonZeroAdjs += east;
countNonZeroAdjs++;
}
if (west != 0) {
sumNonZeroAdjs += west;
countNonZeroAdjs++;
}
if (countNonZeroAdjs > 0) {
curr = sumNonZeroAdjs / countNonZeroAdjs;
}
}
}
}
【问题讨论】:
-
我可以要求简要解释一下收到否决票吗?
-
你已经在 Python 中得到了一个有效的实现。现在你想要一个类似但不同的 c++,用勺子喂给你?我误解了吗?自己懒惰地把它重新写成c++。如果/当您遇到困难时,请提出具体问题。 (没有投反对票,但很想)
-
好的!如果把上面的 sn-p 写成 C++ 让你开心,我很快就会去做。带来不便敬请谅解。请稍候。
-
@enhzflep:我添加了具有相同概念的 CPP 代码。请看一看。显然,迭代这样的图像并不好。不确定inpainting 是否可以提供帮助。
-
“脏孔填充过滤器”?
标签: c++ opencv image-processing