394 Stimmen

Wie erkennt man einen Weihnachtsbaum?

Welche Bildverarbeitungstechniken könnten verwendet werden, um eine Anwendung zu implementieren, die die Weihnachtsbäume erkennt, die in den folgenden Bildern angezeigt werden?

Ich suche nach Lösungen, die mit allen diesen Bildern funktionieren. Daher sind Ansätze, die das Training von haar cascade classifiers oder template matching erfordern, nicht sehr interessant.

Ich suche nach etwas, das in beliebiger Programmiersprache geschrieben werden kann, solange sie nur _Open Source_Technologien verwendet. Die Lösung muss mit den Bildern getestet werden, die in dieser Frage geteilt sind. Es gibt 6 Eingabebilder und die Antwort soll die Ergebnisse der Verarbeitung jedes einzelnen anzeigen. Schließlich müssen für jedes Ausgabebild rote Linien gezeichnet werden, um den erkannten Baum zu umgeben.

Wie würden Sie programmgerecht die Bäume in diesen Bildern erkennen?

23voto

sepdek Punkte 1402

Ein altmodischer Bildverarbeitungsansatz...
Die Idee beruht auf der Annahme, dass Bilder beleuchtete Bäume auf typischerweise dunkleren und glatteren Hintergründen (oder Vordergründen in einigen Fällen) darstellen. Der beleuchtete Baumbereich ist "energetischer" und hat eine höhere Intensität.
Der Prozess läuft wie folgt ab:

  1. In Graustufen umwandeln
  2. LoG-Filterung anwenden, um die aktivsten Bereiche zu erhalten
  3. Eine Intensitätsschwelle anwenden, um die hellsten Bereiche zu erhalten
  4. Die vorherigen 2 kombinieren, um eine vorläufige Maske zu erhalten
  5. Eine morphologische Dilatation anwenden, um Bereiche zu vergrößern und benachbarte Komponenten zu verbinden
  6. Kleine Kandidatenbereiche aufgrund ihrer Größe eliminieren

Das Ergebnis ist eine binäre Maske und ein Begrenzungsrahmen für jedes Bild.

Hier sind die Ergebnisse unter Verwendung dieser naiven Technik: Bildbeschreibung eingeben

Code in MATLAB folgt: Der Code läuft in einem Ordner mit JPG-Bildern. Er lädt alle Bilder und gibt die erkannten Ergebnisse zurück.

% alles löschen
clear;
pack;
close all;
close all hidden;
drawnow;
clc;

% Initialisierung
ims=dir('./*.jpg');
imgs={};
images={}; 
blur_images={}; 
log_image={}; 
dilated_image={};
int_image={};
bin_image={};
measurements={};
box={};
num=length(ims);
thres_div = 3;

for i=1:num, 
    % Originalbild laden
    imgs{end+1}=imread(ims(i).name);

    % In Graustufen umwandeln
    images{end+1}=rgb2gray(imgs{i});

    % Laplace-Filterung und heuristische harte Schwelle anwenden
    val_thres = (max(max(images{i}))/thres_div);
    log_image{end+1} = imfilter( images{i},fspecial('log')) > val_thres;

    % Die hellsten Regionen des Bildes erhalten
    int_thres = 0.26*max(max( images{i}));
    int_image{end+1} = images{i} > int_thres;

    % Die endgültige binäre Abbildung berechnen, indem
    % hohe 'Aktivität' mit hoher Intensität kombiniert wird
    bin_image{end+1} = log_image{i} .* int_image{i};

    % Morphologische Dilatation anwenden, um getrennte Komponenten zu verbinden
    strel_size = round(0.01*max(size(imgs{i})));        % Strukturelement für morphologische Dilatation
    dilated_image{end+1} = imdilate( bin_image{i}, strel('disk',strel_size));

    % Messungen durchführen, um kleine Objekte zu eliminieren
    measurements{i} = regionprops( logical( dilated_image{i}),'Area','BoundingBox');
    for m=1:length(measurements{i})
        if measurements{i}(m).Area < 0.05*numel( dilated_image{i})
            dilated_image{i}( round(measurements{i}(m).BoundingBox(2):measurements{i}(m).BoundingBox(4)+measurements{i}(m).BoundingBox(2)),...
                round(measurements{i}(m).BoundingBox(1):measurements{i}(m).BoundingBox(3)+measurements{i}(m).BoundingBox(1))) = 0;
        end
    end
    % Sicherstellen, dass das dilatierte Bild die gleiche Größe wie das Original hat
    dilated_image{i} = dilated_image{i}(1:size(imgs{i},1),1:size(imgs{i},2));
    % Den Begrenzungsrahmen berechnen
    [y,x] = find( dilated_image{i});
    if isempty( y)
        box{end+1}=[];
    else
        box{end+1} = [ min(x) min(y) max(x)-min(x)+1 max(y)-min(y)+1];
    end
end 

%%% zusätzlicher Code zum Anzeigen
for i=1:num,
    figure;
    subplot(121);
    colormap gray;
    imshow( imgs{i});
    if ~isempty(box{i})
        hold on;
        rr = rectangle( 'position', box{i});
        set( rr, 'EdgeColor', 'r');
        hold off;
    end
    subplot(122);
    imshow( imgs{i}.*uint8(repmat(dilated_image{i},[1 1 3])));

20voto

ifryed Punkte 605

Ich habe Python mit OpenCV verwendet.

Mein Algorithmus funktioniert folgendermaßen:

  1. Es nimmt zuerst den Rotkanal aus dem Bild
  2. Wenden Sie einen Schwellenwert (Minimalwert 200) auf den Rotkanal an
  3. Dann wenden Sie den morphologischen Gradienten an und führen dann einen 'Closing' durch (Dilatation gefolgt von Erosion)
  4. Dann findet es die Konturen in der Ebene und wählt die längste Kontur aus.

Das Ergebnis:

Der Code:

import numpy as np
import cv2
import copy

def findTree(image,num):
    im = cv2.imread(image)
    im = cv2.resize(im, (400,250))
    gray = cv2.cvtColor(im, cv2.COLOR_RGB2GRAY)
    imf = copy.deepcopy(im)

    b,g,r = cv2.split(im)
    minR = 200
    _,thresh = cv2.threshold(r,minR,255,0)
    kernel = np.ones((25,5))
    dst = cv2.morphologyEx(thresh, cv2.MORPH_GRADIENT, kernel)
    dst = cv2.morphologyEx(dst, cv2.MORPH_CLOSE, kernel)

    contours = cv2.findContours(dst,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)[0]
    cv2.drawContours(im, contours,-1, (0,255,0), 1)

    maxI = 0
    for i in range(len(contours)):
        if len(contours[maxI]) < len(contours[i]):
            maxI = i

    img = copy.deepcopy(r)
    cv2.polylines(img,[contours[maxI]],True,(255,255,255),3)
    imf[:,:,2] = img

    cv2.imshow(str(num), imf)

def main():
    findTree('tree.jpg',1)
    findTree('tree2.jpg',2)
    findTree('tree3.jpg',3)
    findTree('tree4.jpg',4)
    findTree('tree5.jpg',5)
    findTree('tree6.jpg',6)

    cv2.waitKey(0)
    cv2.destroyAllWindows()

if __name__ == "__main__":
    main()

Wenn ich den Kernel von (25,5) auf (10,5) ändere, bekomme ich bessere Ergebnisse bei allen Bäumen außer dem unteren linken, Bildbeschreibung hier eingeben

Mein Algorithmus geht davon aus, dass der Baum Lichter hat, und im unteren linken Baum hat das Oberteil weniger Licht als die anderen.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X