在图片中找到美国国旗?
在图片中找到美国国旗?
为庆祝美国独立日,我对找到一种程序化方法来检测图片中的美国国旗很感兴趣。有一个早期且受欢迎的问题涉及在图像中寻找可口可乐罐,它描述了解决该问题的许多好技术,尽管我不确定它们是否适用于国旗,因为:1. 国旗在风中飘扬,因此可能遮挡自己或以非线性方式变形(这使得像SIFT这样的技术有点难以使用)。2. 与可口可乐罐不同,美国国旗的星条旗不是美国国旗独有的,可以是利比里亚的国旗的一部分,排除了许多“线条特征”技术。有没有任何标准的图像处理或识别技术可以特别适用于这个任务?
你可以使用OpenCV库中的“模板匹配”。
这是方法背后的理论:
模板匹配是一种方法,用于在较大的图像中搜索和查找模板图像的位置。OpenCV带有一个名为cv2.matchTemplate()的函数来实现此目的。它只是滑动模板图像覆盖输入图像(如二维卷积)并比较模板和模板图像下的输入图像的补丁。
可以在此处找到代码示例和实现解释:http://docs.opencv.org/master/d4/dc6/tutorial_py_template_matching.html#gsc.tab=0
我的方法将问题推广,并寻找靠近蓝色区域的红白条纹(水平或垂直)模式,因此该方法适用于仅有美国国旗具有该模式的情景。\n\n我的方法用Java开发,使用Marvin Framework。\n\n算法:\n\n1. 颜色过滤器,保留仅为美国国旗的颜色的像素\n2. 查找水平的红白条纹模式\n3. 查找垂直的红白条纹模式\n4. 去除小面积模式(噪声)\n5. 检查该模式是否被蓝色区域包围\n6. 对该区域进行分割\n\n输入:\n\n图片链接\n\n颜色过滤:\n\n图片链接\n\n国旗:\n\n图片链接\n\n当有许多国旗时,表现更加有趣。\n\n输入:\n\n图片链接\n\n颜色过滤:\n\n图片链接\n\n模式匹配:\n\n图片链接\n\n国旗:\n\n图片链接\n\n源代码:\n\n
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; yarea/5){ return true; } return false; } private int[] getCentroid(MarvinImage bin){ long totalX=0, totalY=0, totalPixels=0; for(int y=0; y 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 =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 =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 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(); } }
\n\n其他结果:\n\n图片链接\n\n图片链接\n\n图片链接