为什么任何 OpenCv (C++) 减法运算都会产生全黑图像?
Why does any OpenCv (C++) substract operation result in a full black image?
我想首先说明我当然不是使用 OpenCV 的初学者。但我一直主要在 C# 中使用它,现在我完全迷失在一个我似乎无法解决的 C++ 变体的简单问题上......
问题:每当我使用任何从一个图像中减去另一个图像的操作时,输出图像都是 100% 黑色。每 50 张图像中有 1 张部分显示预期结果,但也部分显示全黑(最后我将 link 示例图像)。澄清一下,全黑是指每个像素值都为 0。在此操作后我预计会有相当多的可见噪声,但 none 存在。
这是我的一段简单的调试代码:
Mat moveImage, stillImage, subst;
while(capture) {
moveImage = CameraClass::cameraVector[0]->imageList.front().clone();
stillImage = CameraClass::cameraVector[0]->imageList.back().clone();
cv::resize(moveImage, moveImage, Size(moveImage.cols * 0.5, moveImage.rows * 0.5), INTER_LINEAR);
cv::resize(stillImage, stillImage, Size(stillImage.cols * 0.5, stillImage.rows * 0.5), INTER_LINEAR);
cv::addWeighted(moveImage, 1, stillImage, -1, 0, subst, CV_8UC1);
stringstream ss, ss2, ss3;
ss << path + "/camtest/image" + to_string(ui32FrameCount) + ".png";
ss2 << path + "/camtest2/image" + to_string(ui32FrameCount) + ".png";
ss3 << path + "/camtest3/image" + to_string(ui32FrameCount) + ".png";
string filepath1 = ss.str();
string filepath2 = ss2.str();
string filepath3 = ss3.str();
cv::imwrite(filepath1, moveImage);
cv::imwrite(filepath2, stillImage);
cv::imwrite(filepath3, subst);
}
我的结果是从 moveImage 和 stillImage 保存的 2 张非常漂亮的图像,而 subst 完全是黑色的。
addWeighted 选项已经是尝试从我这边解决它。我也试过:
cv::subtract(moveImage, stillImage, subst);
还有C++操作:
subst = moveImage - stillImage;
所有结果都是一样的,黑色图像。我尝试以所有这些不同的方式添加图像,输出结果完全没问题。所以它一定是减法运算的结果,也许值低于 0?但是 CV_8UC1 MatType 应该自动截断低于 0 的值吗?
以下是一些示例图像和结果:
Partly black, partly noise (Had to amplify the noise or else it got lost in upload compression)
100% black image result
moveImage frame 1
stillImage frame 1
可能重要的其他信息:
- 我的密码是Threaded/Asynchronous。这段代码示例在一个线程中并且是独立的。由于 moveImage 和 stillImage 都很好,我不明白为什么其他线程或代码会严重影响我的减法操作。 Subst 仅存在于这段代码中,在其他任何地方都无法使用或访问。
- 目前我不会释放我的 Mat 资源。我在调试过程中尝试这样做,但结果没有任何区别。
- 现在所有 3 个 Mat 变量都在这段代码的循环之前声明一次,然后一遍又一遍地使用。我不知道这是否是个问题,但我也已经尝试在每个循环中再次声明它们。
- 此代码的每个循环 stillImage 和 moveImage 都使用来自相机的新帧进行更新。也许减法操作以某种方式在某处保留了引用而不是副本?
- moveImage 和 stillImage 的大小是完全一样的,在整个运行过程中不会改变。
很容易发生 cv::Mat
在列表或数组中共享它们的数据内存,这样如果更新了一个图像,所有图像仍然指向相同的内存。例如,如果捕获在每次迭代中更新相同的 cv::Mat 元素,并且此 cv::Mat 被推回到没有 deep-copying 像素的列表或向量(使用 .clone()
或 .copyTo()
).
std::vector<cv::Mat> buffer;
cv::Mat img;
while(true)
{
bool success = capture.read(img);
//buffer.push_back(img); // in this case Mat objects will share their memory!
buffer.push_back(img.clone()); // this one is ok
}
另一种不太常见的情况是使用已知图像大小初始化 cv::Mat 并创建具有特定大小和 default-object 的容器。在这种情况下,所有 objects 将共享它们的数据内存。
cv::Mat img = cv::Mat::zeros(cv::Size(knownWidth, knownHeight), CV_8UC3);
// WARNING: this initialized element creation will lead to shared memory between different Mat objects in the buffer!
std::vector<cv::Mat> buffer(BUFFER_SIZE, img);
这两种情况的原因是 cv::Mat 基本上是一些引用计数智能 header 可以被复制而不需要复制底层像素内存 space,所以显式 deep-copying 如果不共享内存,则需要数据。
对于此类情况的调试:
确保在您的 function/loop 中,两张图片不相同。您可以使用 cv::absdiff 并通过 > 0 对结果进行阈值处理。如果有任何白色像素,则图像内容不相同。
我想首先说明我当然不是使用 OpenCV 的初学者。但我一直主要在 C# 中使用它,现在我完全迷失在一个我似乎无法解决的 C++ 变体的简单问题上......
问题:每当我使用任何从一个图像中减去另一个图像的操作时,输出图像都是 100% 黑色。每 50 张图像中有 1 张部分显示预期结果,但也部分显示全黑(最后我将 link 示例图像)。澄清一下,全黑是指每个像素值都为 0。在此操作后我预计会有相当多的可见噪声,但 none 存在。
这是我的一段简单的调试代码:
Mat moveImage, stillImage, subst;
while(capture) {
moveImage = CameraClass::cameraVector[0]->imageList.front().clone();
stillImage = CameraClass::cameraVector[0]->imageList.back().clone();
cv::resize(moveImage, moveImage, Size(moveImage.cols * 0.5, moveImage.rows * 0.5), INTER_LINEAR);
cv::resize(stillImage, stillImage, Size(stillImage.cols * 0.5, stillImage.rows * 0.5), INTER_LINEAR);
cv::addWeighted(moveImage, 1, stillImage, -1, 0, subst, CV_8UC1);
stringstream ss, ss2, ss3;
ss << path + "/camtest/image" + to_string(ui32FrameCount) + ".png";
ss2 << path + "/camtest2/image" + to_string(ui32FrameCount) + ".png";
ss3 << path + "/camtest3/image" + to_string(ui32FrameCount) + ".png";
string filepath1 = ss.str();
string filepath2 = ss2.str();
string filepath3 = ss3.str();
cv::imwrite(filepath1, moveImage);
cv::imwrite(filepath2, stillImage);
cv::imwrite(filepath3, subst);
}
我的结果是从 moveImage 和 stillImage 保存的 2 张非常漂亮的图像,而 subst 完全是黑色的。
addWeighted 选项已经是尝试从我这边解决它。我也试过:
cv::subtract(moveImage, stillImage, subst);
还有C++操作:
subst = moveImage - stillImage;
所有结果都是一样的,黑色图像。我尝试以所有这些不同的方式添加图像,输出结果完全没问题。所以它一定是减法运算的结果,也许值低于 0?但是 CV_8UC1 MatType 应该自动截断低于 0 的值吗?
以下是一些示例图像和结果:
Partly black, partly noise (Had to amplify the noise or else it got lost in upload compression)
100% black image result
moveImage frame 1
stillImage frame 1
可能重要的其他信息:
- 我的密码是Threaded/Asynchronous。这段代码示例在一个线程中并且是独立的。由于 moveImage 和 stillImage 都很好,我不明白为什么其他线程或代码会严重影响我的减法操作。 Subst 仅存在于这段代码中,在其他任何地方都无法使用或访问。
- 目前我不会释放我的 Mat 资源。我在调试过程中尝试这样做,但结果没有任何区别。
- 现在所有 3 个 Mat 变量都在这段代码的循环之前声明一次,然后一遍又一遍地使用。我不知道这是否是个问题,但我也已经尝试在每个循环中再次声明它们。
- 此代码的每个循环 stillImage 和 moveImage 都使用来自相机的新帧进行更新。也许减法操作以某种方式在某处保留了引用而不是副本?
- moveImage 和 stillImage 的大小是完全一样的,在整个运行过程中不会改变。
很容易发生 cv::Mat
在列表或数组中共享它们的数据内存,这样如果更新了一个图像,所有图像仍然指向相同的内存。例如,如果捕获在每次迭代中更新相同的 cv::Mat 元素,并且此 cv::Mat 被推回到没有 deep-copying 像素的列表或向量(使用 .clone()
或 .copyTo()
).
std::vector<cv::Mat> buffer;
cv::Mat img;
while(true)
{
bool success = capture.read(img);
//buffer.push_back(img); // in this case Mat objects will share their memory!
buffer.push_back(img.clone()); // this one is ok
}
另一种不太常见的情况是使用已知图像大小初始化 cv::Mat 并创建具有特定大小和 default-object 的容器。在这种情况下,所有 objects 将共享它们的数据内存。
cv::Mat img = cv::Mat::zeros(cv::Size(knownWidth, knownHeight), CV_8UC3);
// WARNING: this initialized element creation will lead to shared memory between different Mat objects in the buffer!
std::vector<cv::Mat> buffer(BUFFER_SIZE, img);
这两种情况的原因是 cv::Mat 基本上是一些引用计数智能 header 可以被复制而不需要复制底层像素内存 space,所以显式 deep-copying 如果不共享内存,则需要数据。
对于此类情况的调试:
确保在您的 function/loop 中,两张图片不相同。您可以使用 cv::absdiff 并通过 > 0 对结果进行阈值处理。如果有任何白色像素,则图像内容不相同。