简体   繁体   English

在图片中找到美国国旗?

[英]Finding the American flag in a picture?

In honor of the Fourth of July, I was interested in finding a programmatic way to detect the American flag in a picture. 为了纪念7月4日,我有兴趣找到一种以编程方式检测图片中的美国国旗。 There is an earlier and popular question about finding Coca-Cola cans in images that describes a number of good techniques for that problem, though I'm not sure that they'll work for flags because 关于在图像找到可口可乐罐头的问题有一个较早且流行的问题,虽然我不确定它们是否适用于旗帜,

  1. flags flutter in the wind and therefore might occlude themselves or otherwise deform nonlinearly (which makes techniques like SIFT a bit harder to use), and 旗帜在风中飘扬,因此可能会遮挡自己或以非线性方式变形(这使得像SIFT这样的技术有点难以使用),以及
  2. unlike a Coca-Cola can, the American flag's Stars and Stripes are not unique to the American flag and could be part of, say, the flag of Liberia , ruling out many "line signature" techniques. 不像可口可乐可以,美国国旗的星条旗不是唯一的美国国旗,并可能是,比如说一部分, 利比里亚国旗 ,排除了很多“行签名”技术。

Are there any standard image processing or recognition techniques that would be particularly suited to this task? 是否有任何标准的图像处理或识别技术特别适合这项任务?

My approach generalizes the problem and in fact looks for a red and white strips pattern (horizontal or vertical) near to a blue region. 我的方法概括了问题,实际上寻找靠近蓝色区域的红色和白色条纹图案(水平或垂直)。 Therefore it works for scenes that only the American flag has this pattern. 因此,它适用于只有美国国旗具有此模式的场景。

My approach is developed in Java and uses Marvin Framework . 我的方法是用Java开发的,并使用Marvin Framework

Algorithm: 算法:

  1. Color filter for keeping only pixels with the same color of American flag. 彩色滤光片仅用于保持美国国旗颜色相同的像素。
  2. Find horizontal red and white strips pattern 找到水平的红色和白色条纹图案
  3. Find vertical red and white strips pattern 找到垂直的红色和白色条纹图案
  4. Remove patterns with small area (noise) 去除面积小(噪音)的图案
  5. Check whether this pattern is surrounded by a blue region 检查此图案是否被蓝色区域包围
  6. Segment the area. 细分区域。

Input: 输入:

在此输入图像描述

Color Filter: 彩色滤光片:

在此输入图像描述

Flag: 旗:

在此输入图像描述

More interesting is the performance in the case there are many flags. 更有趣的是在有很多标志的情况下的性能。

Input : 输入

在此输入图像描述

Color Filter: 彩色滤光片:

在此输入图像描述

Pattern Matching: 模式匹配:

在此输入图像描述

Flag: 旗:

在此输入图像描述

Source Code: 源代码:

import static marvin.MarvinPluginCollection.*;

public class AmericanFlag {

    public AmericanFlag(){
        process("./res/flags/", "flag_0", Color.yellow);
        process("./res/flags/", "flag_1", Color.yellow);
        process("./res/flags/", "flag_2", Color.yellow);
        process("./res/flags/", "flag_3", Color.yellow);
        process("./res/flags/", "flag_4", Color.blue);
    }

    private void process(String dir, String fileName, Color color){
        MarvinImage originalImage = MarvinImageIO.loadImage(dir+fileName+".jpg");
        MarvinImage image = originalImage.clone();
        colorFilter(image);
        MarvinImageIO.saveImage(image, dir+fileName+"_color.png");

        MarvinImage output = new MarvinImage(image.getWidth(), image.getHeight());
        output.clear(0xFFFFFFFF);
        findStripsH(image, output);
        findStripsV(image, output);
        MarvinImageIO.saveImage(output, dir+fileName+"_1.png");

        MarvinImage bin = MarvinColorModelConverter.rgbToBinary(output, 127);
        morphologicalErosion(bin.clone(), bin, MarvinMath.getTrueMatrix(5, 5));
        morphologicalDilation(bin.clone(), bin, MarvinMath.getTrueMatrix(15, 15));
        MarvinImageIO.saveImage(bin, dir+fileName+"_2.png");

        int[] centroid = getCentroid(bin);
        image.fillRect(centroid[0], centroid[1], 30, 30, Color.yellow);

        int area = getMass(bin);
        boolean blueNeighbors = hasBlueNeighbors(image, bin, centroid[0], centroid[1], area);

        if(blueNeighbors){
            int[] seg = getSegment(bin);
            for(int i=0; i<4; i++){
                originalImage.drawRect(seg[0]+i, seg[1]+i, seg[2]-seg[0], seg[3]-seg[1], color);
            }
            MarvinImageIO.saveImage(originalImage, dir+fileName+"_final.png");
        }
    }

    private boolean hasBlueNeighbors(MarvinImage image, MarvinImage bin, int centerX, int centerY, int area){
        int totalBlue=0;
        int r,g,b;
        int maxDistance =  (int)(Math.sqrt(area)*1.2);
        for(int y=0; y<image.getHeight(); y++){
            for(int x=0; x<image.getWidth(); x++){
                r = image.getIntComponent0(x, y);
                g = image.getIntComponent1(x, y);
                b = image.getIntComponent2(x, y);

                if(
                    (b == 255 && r == 0 && g == 0) &&
                    (MarvinMath.euclideanDistance(x, y, centerX, centerY) < maxDistance)
                ){
                    totalBlue++;
                    bin.setBinaryColor(x, y, true);
                }
            }
        }

        if(totalBlue > area/5){
            return true;
        }
        return false;
    }

    private int[] getCentroid(MarvinImage bin){
        long totalX=0, totalY=0, totalPixels=0;
        for(int y=0; y<bin.getHeight(); y++){
            for(int x=0; x<bin.getWidth(); x++){

                if(bin.getBinaryColor(x, y)){
                    totalX += x;
                    totalY += y;
                    totalPixels++;
                }
            }
        }

        totalPixels = Math.max(1, totalPixels);
        return new int[]{(int)(totalX/totalPixels), (int)(totalY/totalPixels)};
    }

    private int getMass(MarvinImage bin){
        int totalPixels=0;
        for(int y=0; y<bin.getHeight(); y++){
            for(int x=0; x<bin.getWidth(); x++){
                if(bin.getBinaryColor(x, y)){
                    totalPixels++;
                }
            }
        }

        return totalPixels;
    }

    private int[] getSegment(MarvinImage bin){
        int x1=-1, x2=-1, y1=-1, y2=-1;
        for(int y=0; y<bin.getHeight(); y++){
            for(int x=0; x<bin.getWidth(); x++){
                if(bin.getBinaryColor(x, y)){

                    if(x1 == -1 || x < x1){ x1 = x; }
                    if(x2 == -1 || x > x2){ x2 = x; }
                    if(y1 == -1 || y < y1){ y1 = y; }
                    if(y2 == -1 || y > y2){ y2 = y; }
                }
            }
        }
        return new int[]{x1,y1,x2,y2};
    }

    private void findStripsH(MarvinImage imageIn, MarvinImage imageOut){

        int strips=0;
        int totalPixels=0;
        int r,g,b;
        int patternStart;
        boolean cR=true;
        int patternLength = -1;
        for(int y=0; y<imageIn.getHeight(); y++){
            patternStart = -1;
            strips = 0;
            patternLength=-1;
            for(int x=0; x<imageIn.getWidth(); x++){
                r = imageIn.getIntComponent0(x, y);
                g = imageIn.getIntComponent1(x, y);
                b = imageIn.getIntComponent2(x, y);

                if(cR){
                    if(r == 255 && g == 0 && b == 0){
                        if(patternStart == -1){ patternStart = x;}
                        totalPixels++;
                    } else{
                        if(patternLength == -1){
                            if(totalPixels >=3 && totalPixels <= 100){
                                patternLength = (int)(totalPixels);
                            } else{
                                totalPixels=0; patternStart=-1; strips=0; patternLength=-1;
                            }
                        } else{
                            if(totalPixels >= Math.max(patternLength*0.5,3) && totalPixels <= patternLength * 2){
                                strips++;
                                totalPixels=1;
                                cR = false;
                            } else{
                                totalPixels=0; patternStart=-1; strips=0; patternLength=-1;
                            }
                        }
                    }
                }
                else{
                    if(r == 255 && g == 255 && b == 255){
                        totalPixels++;
                    } else{
                        if(totalPixels >= Math.max(patternLength*0.5,3) && totalPixels <= patternLength * 2){
                            strips++;
                            totalPixels=1;
                            cR = true;
                        } else{
                            totalPixels=0; patternStart=-1; strips=0; patternLength=-1; cR=true;
                        }
                    }
                }


                if(strips >= 4){
                    imageOut.fillRect(patternStart, y, x-patternStart, 2, Color.black);
                    totalPixels=0; patternStart=-1; strips=0; patternLength=-1; cR=true;
                }
            }
        }
    }

    private void findStripsV(MarvinImage imageIn, MarvinImage imageOut){

        int strips=0;
        int totalPixels=0;
        int r,g,b;
        int patternStart;
        boolean cR=true;
        int patternLength = -1;
        for(int x=0; x<imageIn.getWidth(); x++){
            patternStart = -1;
            strips = 0;
            patternLength=-1;
            for(int y=0; y<imageIn.getHeight(); y++){
                r = imageIn.getIntComponent0(x, y);
                g = imageIn.getIntComponent1(x, y);
                b = imageIn.getIntComponent2(x, y);

                if(cR){
                    if(r == 255 && g == 0 && b == 0){
                        if(patternStart == -1){ patternStart = y;}
                        totalPixels++;
                    } else{
                        if(patternLength == -1){
                            if(totalPixels >=3 && totalPixels <= 100){
                                patternLength = (int)(totalPixels);
                            } else{
                                totalPixels=0; patternStart=-1; strips=0; patternLength=-1;
                            }
                        } else{
                            if(totalPixels >= Math.max(patternLength*0.5,3) && totalPixels <= patternLength * 2){
                                strips++;
                                totalPixels=1;
                                cR = false;
                            } else{
                                totalPixels=0; patternStart=-1; strips=0; patternLength=-1;
                            }
                        }
                    }

//                  if(maxL != -1 && totalPixels > maxL){
//                      totalPixels=0; patternStart=-1; strips=0; maxL=-1;
//                  }
                }
                else{
                    if(r == 255 && g == 255 && b == 255){
                        totalPixels++;
                    } else{
                        if(totalPixels >= Math.max(patternLength*0.5,3) && totalPixels <= patternLength * 2){
                            strips++;
                            totalPixels=1;
                            cR = true;
                        } else{
                            totalPixels=0; patternStart=-1; strips=0; patternLength=-1; cR=true;
                        }
                    }

//                  if(maxL != -1 &&  totalPixels > maxL){
//                      totalPixels=0; patternStart=-1; strips=0; maxL=-1;
//                      cR=true;
//                  }
                }


                if(strips >= 4){
                    imageOut.fillRect(x, patternStart, 2, y-patternStart, Color.black);
                    totalPixels=0; patternStart=-1; strips=0; patternLength=-1; cR=true;
                }
            }
        }
    }

    private void colorFilter(MarvinImage image){

        int r,g,b;
        boolean isR, isB;
        for(int y=0; y<image.getHeight(); y++){
            for(int x=0; x<image.getWidth(); x++){
                r = image.getIntComponent0(x, y);
                g = image.getIntComponent1(x, y);
                b = image.getIntComponent2(x, y);

                isR = (r > 120 && r > g * 1.3 && r > b * 1.3);
                isB = (b > 30 && b < 150 && b > r * 1.3 && b > g * 1.3);

                if(isR){
                    image.setIntColor(x, y, 255,0,0);
                } else if(isB){
                    image.setIntColor(x, y, 0,0,255);
                } else{
                    image.setIntColor(x, y, 255,255,255);
                }
            }
        }
    }

    public static void main(String[] args) {
        new AmericanFlag();
    }
}

Other Results: 其他结果:

在此输入图像描述

在此输入图像描述

在此输入图像描述

You could use 'Template Matching' via the OpenCV library. 您可以通过OpenCV库使用“模板匹配”。

Here is the Theory behind the approach: 以下是该方法背后的理论:

Template Matching is a method for searching and finding the location of a template image in a larger image. 模板匹配是一种在较大图像中搜索和查找模板图像位置的方法。 OpenCV comes with a function cv2.matchTemplate() for this purpose. OpenCV为此提供了一个函数cv2.matchTemplate()。 It simply slides the template image over the input image (as in 2D convolution) and compares the template and patch of input image under the template image. 它只是在输入图像上滑动模板图像(如在2D卷积中),并比较模板图像下的模板和输入图像的补丁。

Code examples and implementation explanation can be found here: http://docs.opencv.org/master/d4/dc6/tutorial_py_template_matching.html#gsc.tab=0 可以在此处找到代码示例和实现说明: http//docs.opencv.org/master/d4/dc6/tutorial_py_template_matching.html#gsc.tab=0

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM