在单个图像中检测多个图像

Posted

技术标签:

【中文标题】在单个图像中检测多个图像【英文标题】:Detecting multiple images in a single image 【发布时间】:2014-01-15 03:51:58 【问题描述】:

我需要帮助来识别边界并将图像与原始图像进行比较。我需要有关如何通过处理或 matlab 或初学者的任何东西来实现这一点的指导。例如看下图。

原图:

多重图像:

【问题讨论】:

所以,what have you tried? 这是一个可能有帮助的类似问题:***.com/q/10168686/2545927 【参考方案1】:

您展示的“多张图片”只需简单的图像处理即可轻松处理,无需模板匹配 :)

% read the second image
img2 = imread('http://i.stack.imgur.com/zyHuj.jpg');
img2 = im2double(rgb2gray(img2));

% detect coca-cola logos
bw = im2bw(img2);                                       % Otsu's thresholding
bw = imfill(~bw, 'holes');                              % fill holes
stats = regionprops(bw, 'Centroid', 'BoundingBox');   % connected components

% show centers and bounding boxes of each connected component
centers = vertcat(stats.Centroid);
imshow(img2), hold on
plot(centers(:,1), centers(:,2), 'LineStyle','none', ...
    'Marker','x', 'MarkerSize',20, 'Color','r', 'LineWidth',3)
for i=1:numel(stats)
    rectangle('Position',stats(i).BoundingBox, ...
        'EdgeColor','g', 'LineWidth',3)
end
hold off

【讨论】:

【参考方案2】:

您可以使用相关方法来定位多个图像:

file1='http://i.stack.imgur.com/1KyJA.jpg';
file2='http://i.stack.imgur.com/zyHuj.jpg';
It = imread(file1);
Ii = imread(file2);
It=rgb2gray(It);
Ii=rgb2gray(Ii);
It=double(It);  % template
Ii=double(Ii);  % image

Ii_mean = conv2(Ii,ones(size(It))./numel(It),'same');
It_mean = mean(It(:));
corr_1 = conv2(Ii,rot90(It-It_mean,2),'same')./numel(It);
corr_2 = Ii_mean.*sum(It(:)-It_mean);
conv_std = sqrt(conv2(Ii.^2,ones(size(It))./numel(It),'same')-Ii_mean.^2);
It_std = std(It(:));
S = (corr_1-corr_2)./(conv_std.*It_std);

imagesc(abs(S))

结果将为您提供最大值的位置:

获取最大值坐标,并将模板质心定位在同一位置,检查模板与匹配图像之间的差异。

我不确定“识别边界”是什么意思,但您总是可以使用精明检测器提取边缘:

bw=edge(It);
bw=imfill(bw,'holes');
figure,imshow(bw)

【讨论】:

我是 matlab 新手,这对我帮助很大,感谢@lennon310 @lennon310 嗨,只是想澄清一下你答案的最后一部分。你如何获得多个位置的局部最大值坐标?【参考方案3】:

下面是一个用Java实现的解决方案,使用Marvin图像处理框架。

方法:

    “原始图像”中加载、分割和缩放 (50x50) 徽标。 在“多张图片”中加载、分割和缩放 (50x50) 每个徽标 对于“多张图片” 中的每个徽标,与“原始图片” 中的徽标进行比较。如果差不多,画一个矩形来突出显示。

比较方法(diff插件内):

对于两个徽标中的每个像素,比较每个颜色分量。如果一个颜色分量的差异高于给定阈值,则认为两个徽标的像素不同。计算不同像素的总数。如果两个徽标的多个不同像素高于另一个阈值,则认为它们不同。 重要提示:这种方法对旋转和透视变化非常敏感。

由于您的示例(“多张图片”)只有古柯徽标,因此我冒昧地添加了另一个徽标以声明算法。

多重图像 2

输出

在另一项测试中,我加入了另外两个类似的古柯徽标。更改阈值参数,您可以指定是想要完全相同的徽标还是接受其变化。在下面的结果中,参数设置为接受徽标变化。

多重图像 3

输出

源代码

public class Logos 

private MarvinImagePlugin threshold = MarvinPluginLoader.loadImagePlugin("org.marvinproject.image.color.thresholding");
private MarvinImagePlugin fill = MarvinPluginLoader.loadImagePlugin("org.marvinproject.image.fill.boundaryFill");
private MarvinImagePlugin scale = MarvinPluginLoader.loadImagePlugin("org.marvinproject.image.transform.scale");
private MarvinImagePlugin diff = MarvinPluginLoader.loadImagePlugin("org.marvinproject.image.difference.differenceColor");

public Logos()

    // 1. Load, segment and scale the object to be found
    MarvinImage target = segmentTarget();

    // 2. Load the image with multiple objects
    MarvinImage original = MarvinImageIO.loadImage("./res/logos/logos.jpg");
    MarvinImage image = original.clone();

    // 3. Segment
    threshold.process(image, image);
    MarvinImage image2 = new MarvinImage(image.getWidth(), image.getHeight());
    fill(image, image2);
    MarvinImageIO.saveImage(image2, "./res/logos/logos_fill.jpg");

    // 4. Filter segments by its their masses
    LinkedHashSet<Integer> objects = filterByMass(image2, 10000);
    int[][] rects = getRects(objects, image2, original);
    MarvinImage[] subimages = getSubimages(rects, original);

    // 5. Compare the target object with each object in the other image
    compare(target, subimages, original, rects);
    MarvinImageIO.saveImage(original, "./res/logos/logos_out.jpg");


private void compare(MarvinImage target, MarvinImage[] subimages, MarvinImage original, int[][] rects)
    MarvinAttributes attrOut = new MarvinAttributes();
    for(int i=0; i<subimages.length; i++)
        diff.setAttribute("comparisonImage", subimages[i]);
        diff.setAttribute("colorRange", 30);
        diff.process(target, null, attrOut);
        if((Integer)attrOut.get("total") < (50*50)*0.6)
            original.drawRect(rects[i][0], rects[i][6], rects[i][7], rects[i][8], 6, Color.green);
        
    


private MarvinImage segmentTarget()
    MarvinImage original = MarvinImageIO.loadImage("./res/logos/target.jpg");
    MarvinImage target = original.clone();
    threshold.process(target, target);
    MarvinImage image2 = new MarvinImage(target.getWidth(), target.getHeight());
    fill(target, image2);
    LinkedHashSet<Integer> objects = filterByMass(image2, 10000);
    int[][] rects = getRects(objects, image2, target);
    MarvinImage[] subimages = getSubimages(rects, original);
    return subimages[0];




private int[][] getRects(LinkedHashSet<Integer> objects, MarvinImage mask, MarvinImage original)
    List<int[]> ret = new ArrayList<int[]>();
    for(Integer color:objects)
        ret.add(getObjectRect(mask, color));
    
    return ret.toArray(new int[0][0]);


private MarvinImage[] getSubimages(int[][] rects, MarvinImage original)
    List<MarvinImage> ret = new ArrayList<MarvinImage>();
    for(int[] r:rects)
        ret.add(getSubimage(r, original));
    
    return ret.toArray(new MarvinImage[0]);


private MarvinImage getSubimage(int rect[], MarvinImage original)
    MarvinImage img = original.subimage(rect[0], rect[1], rect[2], rect[3]);
    MarvinImage ret = new MarvinImage(50,50);
    scale.setAttribute("newWidth", 50);
    scale.setAttribute("newHeight", 50);
    scale.process(img, ret);
    return ret;


private void fill(MarvinImage imageIn, MarvinImage imageOut)
    boolean found;
    int color= 0xFFFF0000;

    while(true)
        found=false;

        Outerloop:
        for(int y=0; y<imageIn.getHeight(); y++)
            for(int x=0; x<imageIn.getWidth(); x++)
                if(imageOut.getIntColor(x,y) == 0 && imageIn.getIntColor(x, y) != 0xFFFFFFFF)
                    fill.setAttribute("x", x);
                    fill.setAttribute("y", y);
                    fill.setAttribute("color", color);
                    fill.setAttribute("threshold", 120);
                    fill.process(imageIn, imageOut);
                    color = newColor(color);

                    found = true;
                    break Outerloop;
                
            
        

        if(!found)
            break;
        
    


private LinkedHashSet<Integer> filterByMass(MarvinImage image, int mass)
    boolean found;
    HashSet<Integer> analysed = new HashSet<Integer>();
    LinkedHashSet<Integer> ret = new LinkedHashSet<Integer>();

    while(true)
        found=false;

        outerLoop:
        for(int y=0; y<image.getHeight(); y++)
            for(int x=0; x<image.getWidth(); x++)
                int color = image.getIntColor(x,y); 
                if(color != 0)
                    if(!analysed.contains(color))
                        if(getMass(image, color) >= mass)
                            ret.add(color); 
                        
                        analysed.add(color);
                        found = true;
                        break outerLoop;
                    
                
            
        

        if(!found)
            break;
        
    
    return ret;


private int getMass(MarvinImage image, int color)
    int total=0;
    for(int y=0; y<image.getHeight(); y++)
        for(int x=0; x<image.getWidth(); x++)
            if(image.getIntColor(x, y) == color)
                total++;
            
        
    
    return total;


private int[] getObjectRect(MarvinImage mask, int color)
    int x1=-1;
    int x2=-1;
    int y1=-1;
    int y2=-1;

    for(int y=0; y<mask.getHeight(); y++)
        for(int x=0; x<mask.getWidth(); x++)
            if(mask.getIntColor(x, y) == color)

                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-x1), (y2-y1);


private int newColor(int color)
    int red = (color & 0x00FF0000) >> 16;
    int green = (color & 0x0000FF00) >> 8;
    int blue = (color & 0x000000FF);

    if(red <= green && red <= blue)
        red+=5;
    
    else if(green <= red && green <= blue)
        green+=5;
    
    else
        blue+=5;
    

    return 0xFF000000 + (red << 16) + (green << 8) + blue;


public static void main(String[] args) 
    new Logos();
   

【讨论】:

【参考方案4】:

您可以使用normxcorr2 函数简化@lennon310 提出的过程:

file1='http://i.stack.imgur.com/1KyJA.jpg';
file2='http://i.stack.imgur.com/zyHuj.jpg';
It = imread(file1);
Ii = imread(file2);
It=rgb2gray(It);
Ii=rgb2gray(Ii);
It=double(It);  % template
Ii=double(Ii);  % image

c=normxcorr2(It, Ii);
imagesc(c); 

【讨论】:

【参考方案5】:

最简单的方法(无需编写任何代码)——使用 Adaptive Vision Studio:

    AddLoadImage(并选择带有多个徽标的图像) 添加 LocateMultipleObjects_EdgeBased。 将来自 LoadImage 的 outImage 连接到来自第二个过滤器的 inImage 从 LocateMultipleObjects_EdgeBased 编辑 inEdgeModel 例如我的编辑结果(使用插件中的加载图像加载模型图像): 运行程序并更改 LocateMultipleObjects_EdgeBased 的参数以查找所有元素(我将 inEdgeMagnitude 更改为 9.0 )。您还将获得每张图片的分数: 结果程序:

总而言之,您需要添加两个过滤器:loadImage 和 LocateMultipleObjects_EdgeBased 并选择要查找的模型 :) 对初学者有好处,您不需要编写任何高级程序。您也可以尝试通过以下方式解决它:检测圆圈、TemplateMatching_NCC 等...

【讨论】:

【参考方案6】:

如果您想在更复杂的环境(旋转、变形、缩放、透视)中检测您的对象,您需要一种更高效的检测方法。我建议你看看所谓的“Haar 特征的级联分类器” OpenCv 可以为您提供很多功能来快速执行此方法。看到这个useful page

或者甚至通过matlab你可以看到这个example

【讨论】:

以上是关于在单个图像中检测多个图像的主要内容,如果未能解决你的问题,请参考以下文章

『cs231n』图像定位与检测

使用 LayerDrawable 相互堆叠的图像数组。(在单个图像视图中显示多个图像)

使用单个几乎相同的参考图像进行物体检测

如何从多个图像中构建单个图像作为一个圆圈?

如何在画布元素中添加超链接到图像?

在单个 UIView 中显示多个图像