java - 红框交通标志的颜色阈值

标签 java c++ opencv image-processing

我想检测所有红框交通标志(三角形和圆形)。该算法必须高效且稳健,才能在现实世界中工作,因此我决定使用 HSV 空间,因为它具有光不变性。

我遇到了这个question检测红色物体的方法,答案是使用 HSV 的这个值范围:代码是 C++ 的:

inRange(hsv, Scalar(0, 70, 50), Scalar(10, 255, 255), mask1);
inRange(hsv, Scalar(170, 70, 50), Scalar(180, 255, 255), mask2);

Mat1b mask = mask1 | mask2;

由于我使用 Java 的 OpenCV,所以我尝试了 that ,但我发现不可能进行按位OR运算。

所以我尝试手动实现它而不是使用 OpenCV。我还尝试了提供的相同红色值范围,遗憾的是结果很糟糕:

这是我的代码

Mat hsv = new Mat();
Mat rgb = Highgui.imread(scene, Highgui.CV_LOAD_IMAGE_COLOR);
Imgproc.cvtColor(rgb, hsv, Imgproc.COLOR_RGB2HSV);
Mat thresh = new Mat(hsv.size(), CvType.CV_8UC1);


for(int x=0;x<hsv.rows();x++){
    for(int y=0;y<hsv.cols();y++)
    {
        double[] data = hsv.get(x,y);

        double H = data[0];
        double S = data[1];
        double V = data[2];
        if((( 0.0>=H && H<=10.0) && (70.0>=S && S<=255.0) && (50.0>=V && V<=255.0)) || (( 170.0>=H && H<=180.0) && (70.0>=S && S<=255.0) && (50.0>=V && V<=255.0)) ) {

            thresh.put(x,y, 255);
        }
        else
        {
            thresh.put(x,y, 0);
        }
    }
}

这是阈值化之前和之后的结果

Original

Threshold

有人能给我提供正确的值(value)观吗?

最佳答案

关键的错误就在一开始:

Mat rgb = Highgui.imread(scene, Highgui.CV_LOAD_IMAGE_COLOR);
Imgproc.cvtColor(rgb, hsv, Imgproc.COLOR_RGB2HSV);

OpenCV C++ API 引用通常是最完整、最详细的,因此引用它总没有坏处。如果你看cv::imread您会注意到以下注释:

In the case of color images, the decoded images will have the channels stored in B G R order.

但是,在您的代码中,您将图像视为 RGB,即交换蓝色和红色。这对你的算法来说是致命的——你正在寻找红色的东西,但任何红色的东西实际上都是蓝色的。

修复方法很简单 - 将 rgb 重命名为 bgr(以避免误导变量名称)并将转换代码更改为 Imgproc.COLOR_BGR2HSV .

我相信您之前的 bitwise_or 问题只是此错误的另一个症状。 (我真的不明白为什么它不起作用)。

请参阅以下示例(使用 OpenCV 3.4.0):

import org.opencv.core.Mat;
import org.opencv.core.Scalar;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;
import org.opencv.core.Core;

public class test
{
    public static void main(String[] args)
    {
        System.loadLibrary(Core.NATIVE_LIBRARY_NAME);

        Mat image = Imgcodecs.imread("test.jpg", Imgcodecs.CV_LOAD_IMAGE_COLOR);
        if ((image == null) || image.empty()) {
            System.out.println("Failed to load input image.");
            System.exit(-1);
        }

        Mat image_hsv = new Mat();
        Imgproc.cvtColor(image, image_hsv, Imgproc.COLOR_BGR2HSV);

        Mat mask1 = new Mat();
        Mat mask2 = new Mat();
        Core.inRange(image_hsv, new Scalar(0, 70, 50), new Scalar(10, 255, 255), mask1);
        Core.inRange(image_hsv, new Scalar(170, 70, 50), new Scalar(180, 255, 255), mask2);

        Mat mask_combined = new Mat();
        Core.bitwise_or(mask1, mask2, mask_combined);

        Mat image_masked = new Mat();
        Core.bitwise_and(image, image, image_masked, mask_combined);

        Imgcodecs.imwrite("test-mask.jpg", mask_combined);        
        Imgcodecs.imwrite("test-masked.jpg", image_masked);

        System.out.println("Done!");
    }
}

这会根据您的示例输入图像生成以下组合蒙版:

Combined mask

如果我们在原始图像上使用这个 mask ,我们可以看到我们确实得到了红色位:

Masked image

关于java - 红框交通标志的颜色阈值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50115325/

相关文章:

c++ - 在 Boost 中的 GCC 3.3 问题下使用 operator() 进行编译

c++ - 初始化类 - 未解析的外部符号

matlab - OpenCV 3 与贡献 matlab 模块构建失败

java - ids 无法解析或不是字段

java - 用于 Alfresco Repository AMP 的 log4j

java - Guava 是否为身份平等提供 Predicates.is(T) (a la Predicates.equalTo(T t))?

c++ - 在 OpenCV 中合并 channel

python - 如何制作 mask 以将除文本以外的所有图像背景设置为白色?

opencv - openCV安装/库问题

java - 原木锻造强化修复