Matlab: Bilderkennung von 12 seitigem Würfel mit Zahlen

(English) Dieser Beitrag ist ähnlich zu dem Beitrag davor und beschreibt die Identifikation von Zahlen  von 1-12 eines 12-seitigen Würfels. Diese Bilder sind ebenfalls in der automatischen Würfelmschine meines Bruder erzeugt worden.

Würfel Identifikation:

Zuerst werden alle Bilder in Matlab geladen und auf eine 200x200 Pixel Größe reduziert. Dieses Bild wird nun konvertiert via rgb2gray in ein farbloses Bild. Darauf hin wird der Gradient angewendet und dieses und das graue Bild werden mit einem Treshold in binäres Bilder umgewandelt.
Das Gradienten Bild wird mit der morphologischen Operation imclose erweitert und dann mit dem normalen binären Bild multipliziert und dann wird Dilatation angewendet um die Konturen dicker zu machen.
Hiernach wird eine große For-Schleife über alle Bilder durchgeführt und die Mitte des Bildes mit meiner Funktion bestimmt (gewichtet alle Stellen die 1 sind und findet die Mitte davon: bestimmt den Mean-Wert aller Zeilen und Spalten an den Stellen an denen das Bild 1 ist). Dann wird ein Gebiet um die Mitte gewählt, welches zu 100% die Zahl enthält (70x70 Pixel).
Dann wird die morphologische Operation watershed angewendet, um zusammenhängende Gebiete zu ermitteln und alle die nicht volständig in dem zuvor gewählten Gebiet sind werden auf 0 gesetzt. Nun wird das größte Gebiet gesucht welches nur eine bestimmte Abweichung von der Mitte haben darf. Dies ist die erste Nummer, die der Würfel zeigt.
Dies wird nun für die nächsten vier größten Gebiete wiederholt, mit der Ausnahme, dass nun die Abweichung zu der Mitte größer eines Wertes sein muss (damit bei der 9 beispielsweise nicht der Kreis miterkannt wird) und die Anzahl der Pixel größer eines Wertes, um Rauschwerte zu vermeiden.
Hiernach werden alle 5 Teile zusammengefügt und erneut die Mitte des Bildes bestimmt mit einer kleinen Umgebung von 51x51 Pixeln ausgeschnitten.
Dann wird der morphologische Operatior skeleton angeendet, welcher aus dem Bild einen 1 Pixel dicke Mitte erzeugt welche mit Dilation auf eine 3 Pixel dicke Zahl vergrößert wird.

Der ganze Prozess kann in den folgenden Bildern nachvollzogen werden (Zeile 1: original Bild, Zeile 2: Treshold Bild, Zeile 3: Treshold mit Gradient, Zeile 4: watershed Bild, Zeile 5: Alle watersheds zusammen, Zeile 6: ausgeschnittene Zahl):

Zahlerkennung:

Zuerst wird von jeder Zahl ein Bild geladen welches als Vergleich gilt. Dieses wird und dann in einer 7x7 Nachbarschaft verschoben damit kleine Abweichungen vermieden werden. So sind 12 Zahlen je 49 Bilder.
In einer großen For-Schleife werden nun über alle Winkel in 1° Schritten und über jede Zahl und jede Zahl in der Nachbarschaft die Differenz von dem zu bearbeitenden Bild bestimmt und in einer großen Matrix gespeichert.
Nun kann das Minimum bestimmt werden und die Zahl bestimmt werden, bei welcher dies aufgetreten ist. Ist die Differenz zu groß oder das Bild ist leer, so wird das Bild als nicht erkannt mit 0 gekennzeichnet.
Mit dieser Methode können auch noch verrauschte Bilder gut erkannt werden und auch die 6 und die 9 (obwohl nur die Stelle des Punktes verschieden ist) gut unterschieden werden.
Durch größere Nachbarschaft kann die Genauigkeit verbessert werden aber dafür benötigt es auch länger.

Speichern:

Es können nun alle Zahlen in individuelle Ordner gespeichert werden und die Anzahl bestimmt werden.
Anzahl 0: 8
Anzahl 1: 154
Anzahl 2: 192
Anzahl 3: 143
Anzahl 4: 180
Anzahl 5: 138
Anzahl 6: 166
Anzahl 7: 169
Anzahl 8: 140
Anzahl 9: 177
Anzahl 10: 185
Anzahl 11: 193
Anzahl 12: 155

und hier sind die fälschlich erkannten Zahlen (für Null bedeutes es, dass 6 mal die 4 fälschlich im Ordner war, 2 mal die 11,
0:    6x4, 2x11, 2xf
1:
2:    
3:    1x2, 1x9
4:   
5:    2x9
6:    4x9
7:    5x1, 1x5
8:    1x2, 1x9
9:   
10:    1x2
11:   
12:

27/2000 Zahlen sind nicht richtig identifiziert worden was für diesen Code ein gutes Resultat ist! Die benötigte Zeit beträgt 20000 Sekunden. Dies kann ebenfalls verbessert werden, wenn die Matrizen nur jeweils ein Bild erhalten, weshalb die Zugreifzeit vermieden wird (13600 Sekunden).

Quellcode:

clear all;
clc;
tic;
iptsetpref('UseIPPL',false);
showgraph = 0;
text_iden = 1;
saveimg = 1;
fold = 'NeuronBilder_D12_03_7_2000';

 %________________________________________________
cd('C:\Users\admin\Dropbox\Sparta Kriegspläne\DieImages\TextHandle');
for i = 1:1:12
    file_num{i} = sprintf('n%d.mat', i);
    num_ex(:,:,i) = cell2mat(struct2cell(load(file_num{i},'-mat')));
end
    neighboor = 7^2;
    n_neigh = (sqrt(neighboor)+1)/2;
    num_small(:,:,:) = num_ex(n_neigh:end+1-n_neigh,n_neigh:end+1-n_neigh,:);
    num_8con(:,:,:,:) = zeros(51,51,12,9);

for i=1:1:sqrt(neighboor)
    for j=1:1:sqrt(neighboor)
        num_8con(i:end+i-sqrt(neighboor),j:end+j-sqrt(neighboor),:,j+sqrt(neighboor)*(i-1)) = num_small(:,:,:);
    end
end
   
    %________________________________________________
cd('C:\Users\admin\Dropbox\Sparta Kriegspläne\DieImages\D12_01x2000');
files = dir('*.jpg');

len = length(files);
%len = 100;
s = 1;
start=0;
    searched_num = [1:1:12];

for i = 1:1:len
    name{i}=files(start+i).name;
    img(:,:,:,i) = im2double(imread(name{i}));
    imgarea(:,:,:) = img(1:200,61:260,:,i);
    img_gray(:,:) = rgb2gray(imgarea(:,:,:));
    img_grad(:,:) = imgradient(img_gray(:,:),'sobel');
    sz = size(img_gray);
    img_oli = img_gray;

    img_tresh = img_oli;
    img_tresh(img_tresh<0.7) = 0;
    img_tresh(img_tresh>=0.7) = 1;

    img_grad(img_grad<0.75) = 0;
    img_grad(img_grad>=0.75) = 1;

    closed = imclose(img_grad,ones(5));
    img_multi = closed.*img_tresh;
    img_multi = imdilate(img_multi,ones(3));

    small_trsh = 50;
    dtm = 15;
    clearvars L_sort L_sum index L_unique L_max L_max_2;   
   
    water = zeros(sz(1),sz(2));
    water_2 = zeros(sz(1),sz(2));
    water_3 = zeros(sz(1),sz(2));
    water_4 = zeros(sz(1),sz(2));
    water_5 = zeros(sz(1),sz(2));
   
    img_water_5(:,:) = zeros(sz(1),sz(2));
    img_water_4(:,:) = zeros(sz(1),sz(2));
    img_water_3(:,:) = zeros(sz(1),sz(2));
    img_water_2(:,:) = zeros(sz(1),sz(2));
    img_water_1(:,:) = zeros(sz(1),sz(2));

    grad_between(:,:) = imgradient(img_multi(:,:),'sobel');
    L(:,:) = watershed(grad_between(:,:));
    L_old = L;
    % find the middle
    [pos_x pos_y] = image_mid(img_tresh(:,:));
    pos_x = pos_x - 18;
    width = 32;
    vec(:,:) = [pos_x-width, pos_x+width; pos_y-width, pos_y+width];
    vec(vec<1) = 1;
    vec(vec>200) = 200;
    %calculate the area L
    water = zeros(sz(1),sz(2));
    L(L==0) = 1;
    % find largest areas
    L_unique = unique(L(:));
    for j=1:1:length(L_unique)
        L_sum(j) = length(L(L==j-1));
    end
    [L_sort, index] = sort(L_sum,'descend');
   
    %1__________________________________________
    L_max = index(2)-1;
    i
    %main img
    water(L(:,:) == L_max) = 1;
    img_water(:,:) = water(:,:);   
    %letter 1
    [pos_x_1 pos_y_1] = image_mid(img_water(:,:));
    area = img_water(vec(1,1):vec(1,2),vec(2,1):vec(2,2));
    sum_1(i) = sum(area(:));
    sum_11(i) = sum(water(:));
    dif_mid_1(i) = ((pos_x-pos_x_1)^2+(pos_y-pos_y_1)^2)^(0.5);
    if sum_11(i)==sum_1(i) && dif_mid_1(i)<35
        img_water(:,:) = water(:,:);
    else
        img_water(:,:) = zeros(sz(1),sz(2));
    end
   
    %2__________________________________________
    L_max_2 = index(3)-1; 
    water_2(L(:,:) == L_max_2) = 1;
    img_water_2(:,:) = water_2(:,:);   
    [pos_x_2 pos_y_2] = image_mid(img_water_2(:,:));
    area = img_water_2(vec(1,1):vec(1,2),vec(2,1):vec(2,2));
    sum_2(i) = sum(area(:));
    sum_22(i) = sum(water_2(:));
    dif_mid_2(i) = ((pos_x_1-pos_x_2)^2+(pos_y_1-pos_y_2)^2)^(0.5);
    %second letter
    if sum_2(i)==sum_22(i) && dif_mid_2(i)>dtm && sum_2(i)>small_trsh
        img_water_2(:,:) = water_2(:,:);
    else
        img_water_2(:,:) = zeros(sz(1),sz(2));
    end
   
    %3__________________________________________
    %third letter
    L_max_3 = index(4)-1;
    water_3(L(:,:) == L_max_3) = 1;
    img_water_3(:,:) = water_3(:,:);
    [pos_x_3 pos_y_3] = image_mid(img_water_3(:,:));
    area_3 = img_water_3(vec(1,1):vec(1,2),vec(2,1):vec(2,2));
    sum_3(i) = sum(area_3(:));
    sum_33(i) = sum(water_3(:));
    dif_mid_3(i) = ((pos_x_1-pos_x_3)^2+(pos_y_1-pos_y_3)^2)^(0.5);
    if sum_3(i)==sum_33(i) && dif_mid_3(i)>dtm && sum_3(i)>small_trsh
        img_water_3(:,:) = water_3(:,:);
    else
        img_water_3(:,:) = zeros(sz(1),sz(2));
    end

    %4__________________________________________
    %forth letter
    if length(index)>4
        L_max_4 = index(5)-1;
        water_4(L(:,:) == L_max_4) = 1;
        img_water_4(:,:) = water_4(:,:);
        [pos_x_4 pos_y_4] = image_mid(img_water_4(:,:));
        area_4 = img_water_4(vec(1,1):vec(1,2),vec(2,1):vec(2,2));
        sum_4(i) = sum(area_4(:));
        sum_44(i) = sum(water_4(:));
        dif_mid_4(i) = ((pos_x_1-pos_x_4)^2+(pos_y_1-pos_y_4)^2)^(0.5);
        if sum_4(i)==sum_44(i) && dif_mid_4(i)>dtm && sum_4(i)>small_trsh
            img_water_4(:,:) = water_4(:,:);
        else
            img_water_4(:,:) = zeros(sz(1),sz(2));
        end
    end
    %5__________________________________________
    %fifth letter
    if length(index)>5
        L_max_5 = index(6)-1;
        water_5(L(:,:) == L_max_5) = 1;
        img_water_5(:,:) = water_5(:,:);
        [pos_x_5 pos_y_5] = image_mid(img_water_5(:,:));
        area_5 = img_water_5(vec(1,1):vec(1,2),vec(2,1):vec(2,2));
        sum_5(i) = sum(area_5(:));
        sum_55(i) = sum(water_5(:));
        dif_mid_5(i) = ((pos_x_1-pos_x_5)^2+(pos_y_1-pos_y_5)^2)^(0.5);
        if sum_5(i)==sum_55(i) && dif_mid_5(i)>dtm && sum_5(i)>small_trsh
            img_water_5(:,:) = water_5(:,:);
        else
            img_water_5(:,:) = zeros(sz(1),sz(2));
        end
    end
   
   
    bet_2 = zeros(sz(1),sz(2));
    bet_2(vec(1,1):vec(1,2),vec(2,1):vec(2,2)) = 1;
    img_rect(:,:) = bet_2(:,:);
    rgb(:,:,:) = label2rgb(L_old(:,:),'jet',[.5 .5 .5]);
   
   
    img_together(:,:) = img_water(:,:) + img_water_2(:,:) + img_water_3(:,:)...
        + img_water_4(:,:) + img_water_5(:,:);
   
    %determine fast area
    [pos_x_n pos_y_n] = image_mid(img_together(:,:));
    width = 25;
    vec_n(:,:) = [pos_x_n-width, pos_x_n+width; pos_y_n-width, pos_y_n+width];
    fast_area(:,:) = zeros(51,51);
    vec_n(vec_n<1) = 1;
    vec_n(vec_n>200) = 200;
    en = vec_n(1,2)-vec_n(1,1)+1;
    en2 = vec_n(2,2)-vec_n(2,1)+1;
    if sum(sum(img_together(:,:)))>50
        fast_area(1:en,1:en2) = img_tresh(vec_n(1,1):vec_n(1,2),vec_n(2,1):vec_n(2,2));
    end

    BW3(:,:) = bwmorph(fast_area(:,:),'skel',Inf);
    BW2 = imdilate(BW3,ones(3));
    BW1 = imdilate(BW3,ones(2));
%___________________
 
    if text_iden == 1
   
    img_ocr = fast_area(:,:);
    img_all{i} = img_ocr;
    angstep=1;
    for angle=1:angstep:360
        img_rot = imrotate(img_ocr,angle,'nearest','crop');
        for j=1:1:12
            for k=1:1:neighboor
                diff_img(:,:) = abs(img_rot-num_8con(:,:,j,k));
                img_diff((angle-1)/angstep+1,j,k) = sum(sum(diff_img));
            end
        end

    end
    for k=1:1:neighboor
        differ_k = img_diff(:,:,k);
        [min_val_k(k) min_pos_k(k)] = min(differ_k(:));
    end
    [minima, minima_pos] = min(min_val_k);
    differ = img_diff(:,:,minima_pos);
    [min_val min_pos] = min(differ(:));
    numbers = min_pos-mod(min_pos,360/angstep);
    letter(i) = numbers/(360/angstep)+1;
    if letter(i) == 0
        letter(i) = 12;
    elseif letter(i) == 5 || letter(i) == 8 || letter(i) == 9
        text_grad = imgradient(img_ocr,'sobel');
        L_text = watershed(text_grad);
        text_unique = length(unique(L_text(:)));
        switch text_unique
            case 3
                letter(i) = 5;
        end
    end
   
    if sum(sum(img_ocr))==0
        letter(i) = 0;
    end
    %subplot(10,10,i);imshow(img_ocr,[]);title(letter(i));


    for i=0:1:12
        c = sprintf('count_%d', i);
        assignin('base', c, length(letter(letter==i)));
    end
    end  
end


% saving __________________________________________________________
if saveimg == 1
    cd('C:\Users\admin\Music');
    mkdir(fold);
    cd(fold);
   
    fid = fopen('Ergebnisse_D12.txt','w');
    for i=0:1:12
        fprintf(fid,'Anzahl %d: %d\r\n',i,length(letter(letter==i)));
    end
    fclose(fid);

    for i=0:1:12
        mkdir(sprintf('%d', i));
    end
   
    for i=1:1:len
        i
        filename = sprintf('C:\\Users\\admin\\Music\\%s\\%d\\img%d_%d.jpg',fold,letter(i),letter(i), i);
        imwrite(img(:,:,:,i),filename);
    end
   
end

time_dur = toc

%_________________________________________________________%
function [pos_x pos_y] = image_mid(image);

[x y] = find(image==1);
pos_x = round(mean(x));
pos_y = round(mean(y));

end

Kommentare

Beliebte Posts aus diesem Blog

Matlab: Fehlergeraden

Matlab: 3D Kartesisches Grid, Vektoren mit Transformation/Rotation

Matlab: Farbspektrum für Plots