关于java:在单个图像中检测多个图像

Detecting multiple images in a single image

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

原始图像:

enter image description here

多重图像:Larger Image


您显示的"多个图像"很容易处理,只需简单的图像处理,不需要模板匹配:)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
% 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

enter image description here


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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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))

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

enter image description here

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

我不确定你所说的"识别边界"是什么意思,但是你可以用Canny探测器提取边缘:

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


下面给出了一个用Java实现的马尔文图像处理框架的解决方案。

途径:

  • 在"原始图像"中加载、分割和缩放(50x50)徽标。
  • 在"多图像"中加载、分割和缩放(50x50)每个徽标
  • 对于"多个图像"中的每个徽标,请与"原始图像"中的徽标进行比较。如果几乎相同,则绘制一个矩形以突出显示。
  • 比较方法(在diff插件中):

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

    由于您的样本("多个图像")只有古柯商标,我冒昧地加入了另一个商标,以断言算法。

    多重图像2

    enter image description here

    产量

    enter image description here

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

    多重图像3

    enter image description here

    产量

    enter image description here

    源代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    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();
    }  
    }

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    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);

    简单的方法(您不需要编写任何代码)-使用自适应视觉工作室:

  • AddLoadImage(并选择带有多个徽标的图像)
  • 添加locatemultipleObjects。
  • 将OutImage从LoadImage连接到第二个筛选器的InImage
  • 从locatemultipleObjects编辑inedgeModel,例如我的编辑结果(使用插件中的加载图像加载模型图像):Model
  • 运行程序并更改locatemultipleObjects的参数以查找所有元素(我将inedgeMigration更改为9.0)。您还将获得每个图像的分数:有结果的程序:enter image description here
  • 总之,您需要添加两个过滤器:LoadImage和locatemultipleObjects,然后选择要查找的模型:)这对初学者很好,您不需要编写任何高级程序。你也可以尝试解决它:检测圆,模板等。


    如果要在更复杂的环境(旋转、变形、缩放、透视)中检测对象,则需要更高效的检测方法。我建议您看看所谓的"haar特性的级联分类器"。opencv可以为您提供很多快速完成这个方法的功能。看到这个有用的页面

    甚至通过matlab,你也可以看到这个例子。