Обнаружение нескольких изображений в одном изображении

Мне нужна помощь для определения границы и сравнения изображений с исходным изображением. Мне нужно руководство по тому, как я могу достичь этого, обработкой или матлабом или что-нибудь для новичка. например, посмотрите на изображение ниже.

Оригинальное изображение:

enter image description here

Несколько изображений: Larger Image

Ответ 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 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

Ответ 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))

Результат даст вам позиции с максимальными значениями:

enter image description here

Получите координаты максимумов и расположите центроид вашего шаблона в том же положении, проверьте разницу между вашим шаблоном и соответствующим изображением.

Я не уверен, что вы подразумеваете под "идентификацией границы", но вы всегда можете извлечь края с помощью canny detector:

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

Ответ 3

Ниже представлено решение, реализованное на Java, с использованием платформы обработки изображений Marvin.

Подход:

  1. Нагрузка, сегмент и масштаб (50x50) - логотип в "исходном изображении".
  2. Нагрузка, сегмент и масштаб (50x50) каждый логотип в "множественном изображении"
  3. Для каждого логотипа в "mulitple image" сравните с логотипом в "оригинальном изображении". Если это почти то же самое, нарисуйте прямоугольник, чтобы выделить.

Метод сравнения (внутри плагина diff):

Для каждого пикселя в двух логотипах сравните каждый компонент цвета. Если разница в одном цветовом компоненте выше, чем заданный порог, считайте, что пиксель отличается для двух логотипов. Вычислите общее количество разных пикселей. Если два логотипа имеют несколько разных пикселей выше другого порога, считайте их разными. ВАЖНО: Этот подход очень чувствителен к вращению и перспективному изменению.

Так как ваш образец ("множественное изображение") имеет только логотипы coca, я взял на себя смелость включить другой логотип, чтобы утверждать алгоритм.

Множественное изображение 2

enter image description here

Вывод

enter image description here

В другом тесте я включил два других похожих логотипа coca. При изменении пороговых параметров вы можете указать, хотите ли вы иметь тот же логотип или принять его варианты. В приведенном ниже результате параметры были установлены для принятия изменений логотипа.

Несколько изображений 3

enter image description here

Вывод

enter image description here

Исходный код

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

Вы можете упростить процесс, предложенный @lennon310, используя функцию normxcorr2:

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:

  1. AddLoadImage (и выберите изображение с несколькими логотипами)
  2. Добавить LocateMultipleObjects_EdgeBased.
  3. Подключите outImage от LoadImage к inImage из второго фильтра
  4. Измените inEdgeModel из LocateMultipleObjects_EdgeBased, например, мой результат редактирования (используйте Load Image в плагине для загрузки образа модели): Model
  5. Запустите программу и измените параметры LocateMultipleObjects_EdgeBased, чтобы найти все элементы (я изменил inEdgeMagnitude на 9.0). Вы также получите оценки для каждого изображения: программа с результатами: enter image description here

В итоге вам нужно добавить два фильтра: loadImage и LocateMultipleObjects_EdgeBased и выбрать модель для поиска :) Это хорошо для новичка, вам не нужно писать какие-либо продвинутые программы. Вы можете попытаться решить эту проблему и путем: обнаружения кругов, TemplateMatching_NCC и т.д. И т.д....

Ответ 6

Если вы хотите, чтобы ваш объект был более сложным (ротация, деформация, масштабирование, перспектива), вам необходим более эффективный метод обнаружения. Я предлагаю вам посмотреть, что называется "каскадным классификатором для функций Хаара". OpenCv может предложить вам много функций для быстрого выполнения этого метода. См. Эту полезную страницу

Или даже в Matlab вы можете увидеть этот пример