Добрый день. Не могу понять в чём ошибка реализации детектора границ Кенни на Delphi6.
Во вложении исходные изображения, углы градиента, градиент и границы. Собель работает вроде верно - очень похоже на то что есть в инете по картинкам, определение углов тоже похоже на правду - стороны света определяются верно на простых перпендикулярных линиях 0-180 градусов с кратностью 45. Сам детектор построен по теории описанной везде - берём точку с углом и градиентом, сравниваем её с соседними точками у которых тот же угол (если 90 то идем вверх и вниз, если 45 то по диагонали проверяем точки), если угол тот же то проверяем градиент на больше/меньше - если у исследуемой точки больше чем у соседних то есть граница и на выходном битмапе ставим белую точку в координату исследуемой.
Куски кода:
код собеля
Код:
FOR Y := BM1.Height-2 DOWNTO 2 DO // перебор матрицы c запасом по краям на 1 пиксель
BEGIN
i1 := BM1.ScanLine[Y-1]; // строка выше
i0 := BM1.ScanLine[Y]; // исследуемая
i2 := BM1.ScanLine[Y+1]; // ниже
d := sobel.ScanLine[Y]; // результат
sba:= sobang.ScanLine[Y]; // массив углов
i := 3; // 3 байта на цвет
FOR X := 2 TO BM1.Width-2 DO
begin
mgx:= -p1*i1^[i-3]-p2*i0^[i-3]-p1*i2^[i-3];
mgx:=mgx +p1*i1^[i+3]+p2*i0^[i+3]+p1*i2^[i+3];
mgy:= -p1*i1^[i-3]-p2*i1^[i]-p1*i1^[i+3];
mgy:=mgy +p1*i2^[i-3]+p2*i2^[i]+p1*i2^[i+3];
ang:=0;
if mgx=0 then mgx:=0.00001;
if (mgx=0)and(mgy=0) then ang:=0;
if mgx<>0 then ang:=trunc(((180/3.1415926)*(ArcTan2(mgy,mgx))));
// if mgy=0 then mgy:=0.00001;
// if (mgy=0)and(mgx=0) then ang:=0;
// if mgy<>0 then ang:=trunc(((180/3.1415926)*(ArcTan2(mgx,mgy))));
mgx:=mgx*mgx;
mgy:=mgy*mgy;
grad:=trunc(sqrt(mgx+mgy)); // вычисляем градиент
if grad<angmin then angmin:=grad;
if grad>angmax then angmax:=grad;
g:=grad;
if grad>255 then g:=255;
GistArray[g]:=GistArray[g]+g;
if GistArray[g]>Gmax then
begin
Gmax:=GistArray[g]; // ищем максимум одинаковых данных
Nmax:=g; // запомнили число
end;
if CheckBox6.Checked then // если надо порог считать, иначе без порога заносим в картинку
if (grad > porog) then grad:= 255
else grad:= 0;
if ((ang<=22)and(ang>=0))or ((ang>=-22)and(ang<=0))then iang:=30 // определяем все углы и им даём цвет
else if (ang>22)and(ang<=67) then iang:=60
else if (ang>67)and(ang<=112) then iang:=90
else if (ang>112)and(ang<=158) then iang:=120
else if (ang<=180)and(ang>158)or((ang>=-180)and(ang<=-158)) then iang:=150
else if (ang>=-158)and(ang<-112) then iang:=180
else if (ang>=-112)and(ang<-67) then iang:=210
else if (ang>=-67)and(ang<=-22) then iang:=240;
d^[i] := grad;
sba^[i]:=iang;
Inc(i);
d^[i] := grad;
sba^[i]:=iang;
Inc(i);
d^[i] := grad;
sba^[i]:=iang;
Inc(i);
end;
END;
код канни
Код:
FOR Y := sobel.Height-2 DOWNTO 2 DO // перебор матрицы c запасом по краям на 1 пиксель
BEGIN
g2 := sobel.ScanLine[Y-1];
g1 := sobel.ScanLine[Y]; // данные амплитуд градиента
g0 := sobel.ScanLine[Y+1];
a2 := sobang.ScanLine[Y-1];
a1 := sobang.ScanLine[Y]; // данные углов
a0 := sobang.ScanLine[Y+1];
e0 := Edgeout.ScanLine[Y]; // приёмное изображение
i := 3; // 3 байта на цвет
FOR X := 2 TO sobel.Width-2 DO
begin
e0^[i]:=0; // очищаем
e0^[i+1]:=0;
e0^[i+2]:=0;
mgg:= g1^[i]; // взяли данные амплитуды
mga:= a1^[i]; // взяли данные угла
if mga=30 then //(ang<=45)and(ang>=0) // определяем все углы и им даём цвет
begin
mgg1:=g1^[i+3]; // направление --> -22+22 =0
mga1:=a1^[i+3];
if mga=mga1 then // если углы направления градиента совпали то выбираем наибольшее значение градиента
if (mgg>mgg1)and(mgg>porog) then begin e0^[i]:=255;e0^[i+1]:=255;e0^[i+2]:=255; end // занулили слабый окончательно
else begin e0^[i]:=0;e0^[i+1]:=0;e0^[i+2]:=0;end
else begin e0^[i]:=255;e0^[i+1]:=255;e0^[i+2]:=255; end;
end // 30
else if mga=60 then //(ang>22)and(ang<=67) =+45
begin
mgg1:=g0^[i+3]; // направление /
mga1:=a0^[i+3];
if mga=mga1 then // если углы направления градиента совпали то выбираем наибольшее значение градиента
if (mgg>mgg1)and(mgg>porog) then begin e0^[i]:=255;e0^[i+1]:=255;e0^[i+2]:=255; end // занулили слабый окончательно
else begin e0^[i+0]:=0;e0^[i+1]:=0;e0^[i+2]:=0; end
else begin e0^[i]:=255;e0^[i+1]:=255;e0^[i+2]:=255; end;
end
else if mga=90 then //(ang>67)and(ang<=115) =+90
begin
mgg1:=g0^[i]; // направление |
mga1:=a0^[i];
if mga=mga1 then // если углы направления градиента совпали то выбираем наибольшее значение градиента
if(mgg>mgg1)and(mgg>porog) then begin e0^[i]:=255;e0^[i+1]:=255;e0^[i+2]:=255; end // занулили слабый окончательно
else begin e0^[i]:=0;e0^[i+1]:=0;e0^[i+2]:=0; end
else begin e0^[i]:=255;e0^[i+1]:=255;e0^[i+2]:=255; end;
end
else if mga=120 then //(ang>115)and(ang<=162) =+135
begin
mgg1:=g0^[i-3]; // направление \
mga1:=a0^[i-3];
if mga=mga1 then // если углы направления градиента совпали то выбираем наибольшее значение градиента
if (mgg>mgg1)and(mgg>porog) then begin e0^[i]:=255;e0^[i+1]:=255;e0^[i+2]:=255; end // занулили слабый окончательно
else begin e0^[i]:=0;e0^[i+1]:=0;e0^[i+2]:=0; end
else begin e0^[i]:=255;e0^[i+1]:=255;e0^[i+2]:=255; end;
end
Может что-то ещё надо? пробывал разбираться с двойным порогом - но толкового описания ненашёл как его реализовать... Вроде как должен убрать шум и двойные границы...
Хелп.
Могу конечно весть проект положить или екзешник, чтобы не собирать его...
Разными пробами кода удавалось получить меньше шума и кое-что похожее на окружности но они были рваные - незамкнутые, в тругих вариантах кода получалось получить боле-менее результат но на переходах углов всегда дырки в контуре..
В картинках - картинка исходник, собель, углы, канни