我想使用OpenCV检测一个对象,它与场景中的其他元素明显不同,因为它是灰色的。这很好,因为我可以用R == G == B进行测试,并且它允许独立于光度,但是逐像素地进行测试很慢。
有没有更快的方法来检测灰色的东西?也许有一个OpenCV方法可以进行R == G == B测试... cv2.inRange
进行颜色阈值处理,这不是我想要的。
答案 0 :(得分:9)
我在Python中找到的最快的方法是使用切片来比较每个通道。经过几次测试后,这种方法比两个嵌套的for循环快200倍。
bg = im[:,:,0] == im[:,:,1] # B == G
gr = im[:,:,1] == im[:,:,2] # G == R
slices = np.bitwise_and(bg, gr, dtype= np.uint8) * 255
这将生成二进制图像,其中灰色对象由白色像素指示。如果您不需要二进制图像,但只需要一个逻辑数组,其中灰色像素由True
值表示,则此方法会更快:
slices = np.bitwise_and(bg, gr)
省略类型转换和乘法产生的方法比嵌套循环快500倍。
在此测试图像上运行此操作:
给出以下结果:
如您所见,正确检测到灰色物体。
答案 1 :(得分:1)
我很惊讶这样一个简单的检查很慢,可能你没有高效编码。
这是一段应该为您完成的短代码。它既不是在速度上也不是在内存中最佳,而是在代码行数中相当:)
std::vector<cv::Mat> planes;
cv::split(image, planes);
cv::Mat mask = planes[0] == planes[1];
mask &= planes[1] == planes[2];
为了它,这里是一个比较,在我看来这是最快的方式(没有并行化)
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <iostream>
#include <vector>
#include <sys/time.h> //gettimeofday
static
double
P_ellapsedTime(struct timeval t0, struct timeval t1)
{
//return ellapsed time in seconds
return (t1.tv_sec-t0.tv_sec)*1.0 + (t1.tv_usec-t0.tv_usec)/1000000.0;
}
int
main(int argc, char* argv[])
{
struct timeval t0, t1;
cv::Mat image = cv::imread(argv[1]);
assert(image.type() == CV_8UC3);
std::vector<cv::Mat> planes;
std::cout << "Image resolution=" << image.rows << "x" << image.cols << std::endl;
gettimeofday(&t0, NULL);
cv::split(image, planes);
cv::Mat mask = planes[0] == planes[1];
mask &= planes[1] == planes[2];
gettimeofday(&t1, NULL);
std::cout << "Time using split: " << P_ellapsedTime(t0, t1) << "s" << std::endl;
cv::Mat mask2 = cv::Mat::zeros(image.size(), CV_8U);
unsigned char *imgBuf = image.data;
unsigned char *maskBuf = mask2.data;
gettimeofday(&t0, NULL);
for (; imgBuf != image.dataend; imgBuf += 3, maskBuf++)
*maskBuf = (imgBuf[0] == imgBuf[1] && imgBuf[1] == imgBuf[2]) ? 255 : 0;
gettimeofday(&t1, NULL);
std::cout << "Time using loop: " << P_ellapsedTime(t0, t1) << "s" << std::endl;
cv::namedWindow("orig", 0);
cv::imshow("orig", image);
cv::namedWindow("mask", 0);
cv::imshow("mask", mask);
cv::namedWindow("mask2", 0);
cv::imshow("mask2", mask2);
cv::waitKey(0);
}
替换图像:
Image resolution=3171x2179
Time using split: 0.06353s
Time using loop: 0.029044s