لبه یابی با canny در دلفی - هفت خط کد انجمن پرسش و پاسخ برنامه نویسی

لبه یابی با canny در دلفی

0 امتیاز
با سلام

یه نمونه کد داخل سایت برنامه نویس گذاشته بودید که خطا میداد

آیا نمونه کدی برای لبه یابی به روش canny دارید؟
سوال شده شهریور 6, 1393  بوسیله ی delphi7_love (امتیاز 22)   2 4 6
دوباره تگ گذاری شد شهریور 6, 1393 بوسیله ی BlueBlade
حداقل مخاطب را هم بفرمائید ما بدونیم با چه کسی صحبت می کنید.
بله درسته ولی ابتدا باید زبان برنامه نویسی رو انتخاب کنیم بعد بریم سراغ مسائل بعدی
ریاضیم زیاد خوب نیست - خوب حالا نتیجه این گفتگو.....
نهایتا.......
1- زبان برنامه نویسی مناسب جهت پردازش تصویر c++
2-ریاضی باید بلد باشی

اگر ریاضی قوی نباشی میشه از نمونه مثال ها استفاده کرد یا خیر
اگر ++C بلد باشید ولی ریاضی رو خیر می تونید از توابع آماده استفاده می کنید ولی کار هایی که میشه انجام داد محدود هستش . مثل راننده ای  که فقط میتونه ماشین رو حرکت بده ولی هیچ اطلاعی از ساختار ماشین نداره و بمحض این که ماشین خراب بشه یا زمانی که بخواد ویژگی جدیدی به ماشین اضافه کنه هیچ کاری از دستش بر نمیاد !
اگر تصمیمتون رو گرفتید که ++C رو شروع کنید این لینک رو ببینید http://goo.gl/KgdLls
برای یادگیری opencv ویرایش دوم کتاب learning opencv کتاب خوبی هست (البته نویسندش فرض کرده که خواننده ++C رو بلد هست )

1 پاسخ

+2 امتیاز

چندین راه  داره یکی مثل همین نمونه کد در ادامه قرار دادم استفاده کنید و گزینه های دیگر استفاده از wrapper غیر رسمی OpenCV و یا اینکه از کتابخانه VisionLIb استفاده کنید.

در ضمن یک نکته ای که باید خدمتون عرض کنم دلفی زبان مناسب برای پردازش تصویر نیست همین کد پایین را اگر ترجمه خط به خط کنی به C++ سرعت 2 برابر میشه اگر هم از C++ به طریق درستی استفاده کنید تا 5 برابر هم می تونید ازتقاء داشته باشید.به هر حال اگر به پردازش تصویر علاقمند باید یا از C++ و یا از wrapper های OpenCV استفاده کنید.

این یک نمونه کد:

unit UCanny;

interface

uses Windows, Graphics, Math,StrUtils, SysUtils;

procedure Canny(const bm_in: TBitmap;const bm_out: TBitmap;
                GaussSize:integer;GaussTheta:single;
                lowerThreshold,upperThreshold,addThreshold:integer;
                ColorMap,Level:integer);

implementation

type
 TLongArray = array[0..65535] of integer;
 PLongArray = ^TLongArray;
 TIntArray = array[0..65535] of integer;


var
 Pbm_In, Pbm_Out: PLongArray;
 tmp_In:array of integer;
 Edge_In:array of integer;
 edgeDir:array of integer;
 gradient:array of integer;
 Hyst:array of integer;

 picth:integer;
 Width,Height:integer;
 ColorMapMode:integer;
 Threshold:integer;




// fonctions diverses...
//==============================================================================

function RGBA(r, g, b, a: Byte): COLORREF;
begin
  Result := (r or (g shl 8) or (b shl 16) or (a shl 24));
end;

function ArcEnCiel(a:integer):integer;
begin
  while a<0 do a:=a+360;
  Case (a div 60) mod 6 of
      0: result:=RGB(255 ,17*(a Mod 60) shr 2,  0);
      1: result:=RGB(255-17*(a Mod 60) shr 2 ,255 ,  0);
      2: result:=RGB(  0 ,255 ,17*(a Mod 60) shr 2);
      3: result:=RGB(  0 ,255-17*(a Mod 60) shr 2 ,255);
      4: result:=RGB(17*(a Mod 60) shr 2,  0 ,255);
      5: result:=RGB(255 ,  0 ,255-17*(a Mod 60) shr 2);
   end;
end;


function RGBtoGray(c:longint):longint;
var
 r,g,b:cardinal;
begin
  r := (c and $FF0000)   shr 16;
  g := (c and $00FF00) shr  8;
  b := (c and $0000FF) ;

  c:=(r*30+g*59+b*11) div 100;
  result :=$010101*byte(c);
end;

//==============================================================================

function getPixel(pt:pointer;xx,yy:integer):longint;
begin
 result:=0;
 if xx<0 then xx:=0;
 if yy<0 then yy:=0;
 if xx>Width-1 then xx:=Width-1;
 if yy>Height-1 then yy:=Height-1;
 result:= PLongArray(pt)[xx+yy*Width];
end;

procedure SetPixel(pt:pointer;xx,yy,px:integer);
begin
 PLongArray(pt)[xx+yy*Width]:=px;
end;

function getBytePixel(pt:pointer;xx,yy:integer):longint;
begin
 result:=0;
 if xx<0 then xx:=0;
 if yy<0 then yy:=0;
 if xx>Width*4-1 then xx:=Width*4-4+xx mod 4;
 if yy>Height-1 then yy:=Height-1;
 result:= PByteArray(pt)[xx+yy*Width*4];
end;

procedure SetBytePixel(pt:pointer;xx,yy,px:integer);
begin
 if xx<0 then exit;
 if yy<0 then exit;
 if xx>=Width*4 then exit;
 if yy>=Height then exit;
 PByteArray(pt)[xx+yy*Width*4]:=px;
 if ColorMapMode<>1 then
  begin
   PByteArray(pt)[xx+1+yy*Width*4]:=px;
   PByteArray(pt)[xx+2+yy*Width*4]:=px;
   PByteArray(pt)[xx+3+yy*Width*4]:=px;
  end;
end;

procedure copyimage(pt_In,pt_Out:pointer);
var
 i,j:integer;
begin
 for j:=0 to Height-1 do for i:=0 to Width-1 do
      SetPixel(pt_Out,i,j,GetPixel(pt_In,i,j));
end;

//==============================================================================

procedure ColorGradient;
var
 i,j:integer;
begin
 for j:=0 to Height-1 do for i:=0 to Width-1 do
            SetPixel(Pbm_Out,i,j,arcenciel(GetBytePixel(PLongArray(gradient),i*4,j)));
end;

procedure ColorDirection;
var
 i,j:integer;
const
 EdgeColor:array[0..3] of tcolor=($000001,$010000,$010100,$000100);
begin
 for j:=0 to Height-1 do for i:=0 to Width-1 do
            SetPixel(Pbm_Out,i,j,EdgeColor[GetBytePixel(PLongArray(edgeDir),i*4,j)]
                           *GetBytePixel(PLongArray(gradient),i*4,j));
end;

// passe l'image en niveau de gris
//==============================================================================
procedure MakeGrayScale;
var
 i,j:integer;
 c:integer;
begin
 for j:=0 to Height-1 do for i:=0 to Width-1 do
 case ColorMapMode of
 0: SetPixel(PLongArray(Tmp_In),i,j,RGBtoGray(GetPixel(Pbm_In,i,j)));
 1: SetPixel(PLongArray(Tmp_In),i,j,getPixel(Pbm_In,i,j));
 2: SetBytePixel(PLongArray(Tmp_In),i*4,j,getbytePixel(Pbm_In,i*4+2,j));
 3: SetBytePixel(PLongArray(Tmp_In),i*4,j,getbytePixel(Pbm_In,i*4+1,j));
 4: SetBytePixel(PLongArray(Tmp_In),i*4,j,getbytePixel(Pbm_In,i*4+0,j));
 end;
end;


// applique un flou gaussien
//==============================================================================

procedure GaussianBlur(size:integer;theta:single);
var
 i,j,x,y:integer;
 col:single;
 c:dword;
 theta2:single;
 GaussSum:single;
 GaussMatrice:array of array of single;
begin
 // si la taille est 1, il n'y a pas de flou...
 if size=1 then
  begin
   for j:=0 to Height-1 do for i:=0 to Width-1 do
     SetPixel(Pbm_Out,i,j,getPixel(Pbm_In,i,j));
   exit;
  end;

 // calcul la matrice pour le filtre
 theta2:=2*theta*theta;
 size:=size-1;
 setlength(GaussMatrice,size*2+1);
 GaussSum:=0;
 for j:=-size to size do
  begin
    setlength(GaussMatrice[size+j],size*2+1);
    for i:=0 to size-1 do
     begin
      GaussMatrice[size+j,size+i]:=exp(-(j*j+i*i)/theta2)/(pi*theta2);
      GaussSum:=GaussSum+GaussMatrice[size+j,size+i];
      if i=0 then continue;
      GaussMatrice[size+j,size-i]:=GaussMatrice[size+j,size+i];
      GaussSum:=GaussSum+GaussMatrice[size+j,size+i];
     end;
  end;

 // on applique la matrice
 for j:=0 to Height-1 do
  for i:=0 to Width*4-1 do
   if (ColorMapMode<>1) and (i mod 4<>0) then continue
   else
   begin
    col:=0;
    for y:=-size to size do for x:=-size to size do
     begin
      c:=getBytePixel(PLongArray(Tmp_In),i+x*4,j+y);
      col:=col+GaussMatrice[size+x,size+y]*c;
     end;
    SetBytePixel(Pbm_Out,i,j,round(col/GaussSum));
   end;
end;

// applique le filtre de Sobel qui recherche les contours suivant X et Y
//==============================================================================

const
 Matrice_Sobel_x:array[-1..1,-1..1] of integer=((-1,0,1),  (-2,0,2),  (-1,0,1));
 Matrice_Sobel_y:array[-1..1,-1..1] of integer=((1,2,1),  (0,0,0),  (-1,-2,-1));

procedure Sobel;
var
 i,j,x,y:integer;
 colx,coly:integer;
 c:dword;
 angle:integer;
begin
  // on efface le tableau
 for j:=0 to Height-1 do for i:=0 to Width-1 do SetPixel(PLongArray(gradient),i,j,0);
 for j:=0 to Height-1 do for i:=0 to Width-1 do SetPixel(PLongArray(edgeDir),i,j,0);

 for j:=1 to Height-2 do
  for i:=4 to Width*4-5 do
   if (ColorMapMode<>1) and (i mod 4<>0) then continue
   else
   begin
    colx:=0;
    coly:=0;
    for y:=-1 to 1 do for x:=-1 to 1 do
     begin
      c:=getBytePixel(Pbm_Out,i+x*4,j+y);
      colx:=colx+Matrice_Sobel_x[x,y]*c;
      coly:=coly+Matrice_Sobel_y[x,y]*c;
     end;
    SetBytePixel(PLongArray(gradient),i,j,round(sqrt(colx*colx+coly*coly)));
    angle:=round((ArcTan2(colx,coly)*180/pi+202.5)/45) mod 4;
    SetBytePixel(PLongArray(edgeDir),i,j,angle);
   end;
end;

// trace un trait sur chaque contour
//==============================================================================
procedure findEdge(x_Shift,y_Shift, x, y:integer);
var
  g1,g2,g:integer;
begin
 g:=GetBytePixel(PLongArray(gradient),x,y);
 g1:=GetBytePixel(PLongArray(gradient),x+x_Shift,y+y_Shift);
 g2:=GetBytePixel(PLongArray(gradient),x-x_Shift,y-y_Shift);
 if (g>g1) and (g>g2) then SetBytePixel(Pbm_Out,x,y,g)
                      else SetBytePixel(Pbm_Out,x,y,0);
end;

procedure TraceAllEdges;
var
 i,j:integer;
begin
 for j:=1 to Height-2 do
  for i:=4 to Width*4-5 do
   if (ColorMapMode<>1) and (i mod 4<>0) then continue
   else
   begin
     case GetBytePixel(PLongArray(edgeDir),i,j) of
       0:findEdge( 4, 0, i, j);
       1:findEdge(-4, 1, i, j);
       2:findEdge( 0, 1, i, j);
       3:findEdge( 4, 1, i, j);
     end;
   end;
end;

// cherche les points maxi sur les contours et efface les autres
//==============================================================================

procedure suppressNonMax( i, j, lowerThreshold:integer);
begin
 // pas assez blanc
 if GetBytePixel(Pbm_Out,i,j)<=lowerThreshold then exit;
 // déjà vu
 if GetBytePixel(PLongArray(Hyst),i,j)=255 then exit;

 SetBytePixel(PLongArray(Hyst),i,j,255);
 SetBytePixel(Pbm_Out,i,j,255);
 suppressNonMax(i-4,j-1,lowerThreshold);
 suppressNonMax(i  ,j-1,lowerThreshold);
 suppressNonMax(i+4,j-1,lowerThreshold);
 suppressNonMax(i-4,j  ,lowerThreshold);
 suppressNonMax(i+4,j  ,lowerThreshold);
 suppressNonMax(i-4,j+1,lowerThreshold);
 suppressNonMax(i  ,j+1,lowerThreshold);
 suppressNonMax(i+4,j+1,lowerThreshold);
end;

procedure Hysteresis(lowerThreshold,upperThreshold:integer);
var
 i,j:integer;
begin
 // on efface le tableau
 for j:=0 to Height-1 do for i:=0 to Width-1 do SetPixel(PLongArray(Hyst),i,j,0);

 // on crée un cadre noir autour
 for j:=0 to Height-1 do SetPixel(Pbm_Out,0,j,0);
 for j:=0 to Height-1 do SetPixel(Pbm_Out,Width-1,j,0);
 for i:=0 to Width-1 do SetPixel(Pbm_Out,i,0,0);
 for i:=0 to Width-1 do SetPixel(Pbm_Out,i,Height-1,0);

 for j:=0 to Height-1 do for i:=0 to Width*4-1 do
  if (ColorMapMode<>1) and (i mod 4<>0) then continue
   else
         begin
      // point dejà traité, on passe au suivant
      if GetBytePixel(PLongArray(Hyst),i,j)=255 then continue;
      // pas assez blanc pour le traitement
            if GetBytePixel(Pbm_Out,i,j)<upperThreshold then continue;
           suppressNonMax( i, j, lowerThreshold);
         end;
end;

procedure ClearNonWhitePixel;
var
 i,j:integer;
 c:integer;
begin
  for j:=0 to Height-1 do for i:=0 to Width*4-1 do
  if (ColorMapMode<>1) and (i mod 4<>0) then continue
   else
         begin
      c:=GetBytePixel(Pbm_Out,i,j);
            if c<255 then SetBytePixel(Pbm_Out,i,j,0);
         end;
end;


//------------------------------------------------------------------------------
//==============================================================================


function CountNeighbors(i,j:integer):integer;
begin
 result:=0;
 if GetBytePixel(Pbm_Out,i,j)=0 then exit;

 if GetBytePixel(Pbm_Out,i+4,j+1)<>0 then inc(result);
 if GetBytePixel(Pbm_Out,i  ,j+1)<>0 then inc(result);
 if GetBytePixel(Pbm_Out,i-4,j+1)<>0 then inc(result);

 if GetBytePixel(Pbm_Out,i+4,j  )<>0 then inc(result);
 if GetBytePixel(Pbm_Out,i-4,j  )<>0 then inc(result);

 if GetBytePixel(Pbm_Out,i+4,j-1)<>0 then inc(result);
 if GetBytePixel(Pbm_Out,i  ,j-1)<>0 then inc(result);
 if GetBytePixel(Pbm_Out,i-4,j-1)<>0 then inc(result);
end;

type
 TMatrisse=array[1..6] of tpoint;
const
 Matrisses   : array[0..3] of TMatrisse=(
 ((x:-4;y:-1),(x:+0;y:-1),(x:+4;y:-1),(x:-4;y:+1),(x:+0;y:+1),(x:+4;y:+1)), //Matrisse_N_S
 ((x:+0;y:+1),(x:+4;y:+1),(x:+4;y:+0),(x:-4;y:-0),(x:-4;y:-1),(x:-0;y:-1)), //Matrisse_NE_SW
 ((x:-4;y:-1),(x:-4;y:+0),(x:-4;y:+1),(x:+4;y:-1),(x:+4;y:+0),(x:+4;y:+1)), //Matrisse_E_W
 ((x:-4;y:+0),(x:-4;y:+1),(x:-0;y:+1),(x:+4;y:-0),(x:+4;y:-1),(x:+0;y:-1))  //Matrisse_NW_SE
 );

procedure findNextEdge(x, y:integer;mat:TMatrisse);
var
 fn,dx,dy:integer;
 g:array[1..6] of integer;
 m,i,j:integer;
begin
 m:=0;
 for i:=1 to 6 do
  begin
   g[i]:=GetBytePixel(PLongArray(gradient),x+mat[i].X,y+mat[i].Y);
   if GetBytePixel(Pbm_Out,x+mat[i].X,y+mat[i].Y)<>0 then g[i]:=0;
   if g[i]>Threshold then m:=1;
  end;
 // pas de voisin avec in gradient assez haut
 if m=0 then exit;

 m:=0;
 j:=0;
 for i:=1 to 6 do if g[i]>m then begin m:=g[i];j:=i; end;
 dx:=mat[j].X;
 dy:=mat[j].y;
 SetBytePixel(Pbm_Out,x+dx,y+dy,255);
 if CountNeighbors(x+dx,y+dy)=1 then
  findNextEdge(x+dx,y+dy,Matrisses[GetBytePixel(PLongArray(edgeDir),x+dx,y+dy)]);
end;


procedure AddEgde;
var
 i,j:integer;
begin
 for j:=1 to Height-2 do
  for i:=4 to Width*4-5 do
   if (ColorMapMode<>1) and (i mod 4<>0) then continue
   else
   begin
     if CountNeighbors(i,j)=1 then
       findNextEdge(i,j,Matrisses[GetBytePixel(PLongArray(edgeDir),i,j)]);

   end;
end;

//==============================================================================
//==============================================================================



procedure Canny(const bm_in: TBitmap;const bm_out: TBitmap;
                GaussSize:integer;GaussTheta:single;
                lowerThreshold,upperThreshold,addThreshold:integer;
                ColorMap,Level:integer);
begin
 // initialisation des variables
 Width :=bm_In.Width;
 Height:=bm_In.Height;

 bm_Out.Width:=bm_In.Width;
 bm_Out.Height:=bm_In.Height;

 bm_In.PixelFormat := pf32bit;
 bm_Out.PixelFormat := pf32bit;

 picth:=bm_In.Width*4;

 Pbm_In := PLongArray(bm_In.ScanLine[bm_In.Height-1]);
 Pbm_Out := PLongArray(bm_Out.ScanLine[bm_Out.Height-1]);

 setlength(Tmp_In,Width*Height*4);
 setlength(edgeDir,Width*Height*4);
 setlength(gradient,Width*Height*4);
 setlength(Hyst,Width*Height*4);

 ColorMapMode:=ColorMap;
 Threshold:=addThreshold;

 //traitement de l'image
 MakeGrayScale;
    if level=0 then begin copyimage(PLongArray(Tmp_In),Pbm_Out); exit; end;
 GaussianBlur(GaussSize,GaussTheta);
    if level=1 then exit;
 Sobel;
    if level=2 then begin ColorGradient; exit; end;
    if level=3 then begin ColorDirection; exit; end;

 TraceAllEdges;
    if level=4 then exit;

 Hysteresis(lowerThreshold,upperThreshold);
    if level=5 then exit;
 ClearNonWhitePixel;
    if level=6 then exit;

 AddEgde;

end;

{
  Level=
    0:GrayScale
    1:Gaussian Blur
    2:Sobel Gradient
    3:Sobel Direction
    4:Find Edge
    5:Hysteresis
    6:Complete
}

end.

 

پاسخ داده شده شهریور 6, 1393 بوسیله ی مصطفی ساتکی (امتیاز 21,998)   24 34 75
با تشکر
از شما
PLongArray
 خطا میگیره
بنده حامد جوانمرد هستم
کدو من ننوشتم .برای شما پیداش کردم .debug کنید خودتون خطاشو رفع کنید.
من تشخیص پلاک آقای گلبافان رو دیدم که ظاهرا از سرعت خوبی برخورداره و با دلفی نوشته شده
و با چند نفر که مشورت گرفتم پیشنهادشون دلفی و c++ بود
ولی خود من بیشتر با دلفی و سی شارپ کار کردم
پیشنهاد شما روی کدام زبان است
لطفا با ذکر علت
و نمونه کد برای دلفی بیشتر است یا c++
ممنون از توجهتون
دوست عزیز من سال 85 با دلفی پلاک خوان نوشتم خیلی هم بهینه بود ولی بعدش با c++ آشنا شدم تازه سرعت و کارایی را درک کردم.نه دلفی و نه C# هیچ کدام از این 2 زبان برای پردازش تصویر مناسب نیست.دیگه مباحث optimize خیلی تخصصی شده و اکثرشون فقط در c++  قابل استفاده هستند و تنها راهشون هم استفاده از wrapper هاست که با آن خیلی محدود هستید و از امکانات c++ نمی تونید به طور کامل استفاده کنید.
میشه در مورد wrapper توضیح بدید یعنی چی؟
و اینکه من که با c++ کار نکردم و هنوز حتی نرم افزار شو باز نکردم به نظر شما چقدر زمان نیاز هست بذارم که برم روی c++?
و در مورد opencv هم یه توضیح مختصر بدید که منظور کتابخانه های آماده c++ هست یا نه
لطفاً بجای استفده از کلید پاسخ از کلید دیدهگاه استفاده کنید (راهنمای سایت را مطالعه کنید).
wrapper یعنی کد دلفی که میاد از کتابخانه که با زبان دیگه نوشته شده استفاده می کنه .حتی خود دلفی هم از توابع ویندوز به شکل wrapper استفاده می کنه خیلی از کلاس های vcl.
این هم یک wrapper خوبه OpenCV برای دلفی هستش.
https://github.com/Laex/Delphi-OpenCV

یادگیری زبان c++ به نظر من بستگی نداره به تلاش و توانایی های شما بستگی داره در ضمن فقط زبان مسئله نیست خود پردازش تصویر یعنی مباحث ریاضیات به این فیلد هم باید مسلط باشید نباشید کارهاتون زیاد جالب از آب در نمیاد.
...