18. februar 2012 - 19:17Der er
13 kommentarer og 1 løsning
Find billede kant i billede
Jeg har et billede (TImage), billedet består af en ensfarvet baggrund og ca. i midten er der et andet kvadratisk billede af f.eks. et blad. Det jeg skal er at finde left, right, top og bottom for bladet. Det skal siges at den ensfarvet baggrund ikke er 100% ensfarvet da billedet er taget med et kamera.
type TForm1 = class(TForm) Image1: TImage; procedure FormCreate(Sender: TObject); private public end;
var Form1: TForm1;
implementation
{$R *.dfm}
const NONE = $00;
type pRgb=^tRgb; tRgb=record b,g,r:byte end;
function inRange(i,a,b:longInt):boolean; begin result:=(i>=a) and (i<=b) end;
function bmp24isLineX(bmp:tBitmap;y,x1,x2:word;aSens:byte=NONE):boolean; var p,eP:pChar;r1,g1,b1:byte; begin result:=false; if (y>=bmp.height) or (x1>=bmp.width) or (x2<=x1) or (x2>=bmp.width) then exit; p:=x1*3+pChar(bmp.scanLine[y]);eP:=succ(x2-x1)*3+p; b1:=pByte(p)^;g1:=pByte(p+1)^;r1:=pByte(p+2)^;inc(p,3);//get first pixel while p<eP do with pRgb(p)^ do begin if aSens<>NONE then begin//with sensivity if not inRange(longInt(r),r1-aSens,r1+aSens) then exit; if not inRange(longInt(g),g1-aSens,g1+aSens) then exit; if not inRange(longInt(b),b1-aSens,b1+aSens) then exit; end else if (r<>r1) or (g<>g1) or (b<>b1) then exit;//without sensivity inc(p,3) end;result:=true end;
function bmp24isLineY(bmp:tBitmap;x,y1,y2:word;aSens:byte=NONE):boolean; var p:pChar;r1,g1,b1:byte; begin result:=false; if (x>=bmp.width) or (y1>=bmp.height) or (y2<=y1) or (y2>=bmp.height) then exit; p:=x*3+pChar(bmp.scanLine[y1]); b1:=pByte(p)^;g1:=pByte(p+1)^;r1:=pByte(p+2)^;//get first pixel for y1:=y1+1 to y2 do begin p:=x*3+pChar(bmp.scanLine[y1]); with pRgb(p)^ do if aSens<>NONE then begin//with sensivity if not inRange(longInt(r),r1-aSens,r1+aSens) then exit; if not inRange(longInt(g),g1-aSens,g1+aSens) then exit; if not inRange(longInt(b),b1-aSens,b1+aSens) then exit; end else if (r<>r1) or (g<>g1) or (b<>b1) then exit//without sensivity end;result:=true end;
function bmpCropRect24(bmp:tBitmap;var x1,y1,x2,y2:word;aSens:byte=20):boolean;//find auto crop dimensions from TBitmap var bl,bl2:boolean; begin result:=false; with bmp do begin if (pixelFormat<>pf24bit) or (width<8) or (height<8) then exit; x1:=NONE;y1:=NONE;x2:=pred(bmp.width);y2:=pred(bmp.height); while (y2>y1) and (x2>x1) do begin bl2:=false; bl:=true;while bl and (y2>y1) and (x2>x1) do if bmp24isLineX(bmp,y1,x1,x2,aSens) then begin inc(y1);bl2:=true end else bl:=false;//Y1 (TOP) bl:=true;while bl and (y2>y1) and (x2>x1) do if bmp24isLineX(bmp,y2,x1,x2,aSens) then begin dec(y2);bl2:=true end else bl:=false;//Y2 (BOTTOM) bl:=true;while bl and (y2>y1) and (x2>x1) do if bmp24isLineY(bmp,x1,y1,y2,aSens) then begin inc(x1);bl2:=true end else bl:=false;//X1 (LEFT) bl:=true;while bl and (y2>y1) and (x2>x1) do if bmp24isLineY(bmp,x2,y1,y2,aSens) then begin dec(x2);bl2:=true end else bl:=false;//X2 (RIGHT) if bl2 then result:=true else break end end end;
const CROPPING_SENSIVITY = 20;
procedure TForm1.FormCreate(Sender: TObject); var bmp:tBitmap;jpg:tJpegImage;x1,y1,x2,y2:word; begin jpg:=tJpegImage.create; bmp:=tBitmap.create;
if bmpCropRect24(bmp,x1,y1,x2,y2,CROPPING_SENSIVITY) then with bmp.canvas do begin pen.color:=clYellow; brush.style:=bsClear; rectangle(x1,y1,x2,y2); end;
Jeg venter og ser om der kommer andre forslag. Koden virker næsten hvis jeg sætter CROPPING_SENSIVITY op til 60 men dog ikke godt nok til at det er brugbart, desuden er det for langsomt. Jeg tror ikke det jeg har brug for behøver at være så "omfattende", jeg tror det er nok blot at kikke på hver f.eks. 50. Y linie i billedet. Emnet der er foran den "ensfarvede" baggrund står altid i midten så mht. TOP og BOTTOM så er det nok blot at gå ned/op fra midten af TImage dvs. X=Image.width/2. Og når TOP/BOTTOM er fundet så gå ned/op derfra for af finde min/max for LEFT og RIGHT.
Ok, ærgeligt det ikke virker for dig. Det virker nu fint her til at fjerne sorte rammer på youtube video miniaturer osv. men det er så vidt jeg forstår også et andet formål.
Du kommer ikke udenom at scanne alle pixels, for ellers ricikeres at fjerne tekst med småt eller andre detaljer. Og performance, ja der er to ting som sløver en smule, at den i lineY kører scanline på hver linie, og så at den gentager processen indtil det "nuværende" billede ikke har rammer... Men var skrevet til et andet billede format i første omgang som ikke bruger scanline..
Det er muligt der findes en anden fremgangsmåde, i så fald vil jeg gerne se den.
Jeg har en video-stream, hvor jeg kan styre billedhastigheden (altså frame-raten). Opgaven er, at jeg skal detektere eventuelle forskelle mellem billederne og hvis en billedsekvens er sort, er dette at betragte som slut på sekevens.
Hidtil gør jeg det på følgende måde: Gemmer frame N som et BMP-picture. Gennem-analyserer BMP (frame 1) billedet (på pixelniveau (BMP-formatet viser X-size og Y-size, Bits per Pixel osv) og hvor de forskellige billedlinier starter (og slutter)).
Henter frame 2 og sammenligner med Frame 1 (på array-niveau). Der vil altid være forskelle men er disse forskelle over en vis pct.del betragtes billedet som forskelligt. Dette gentages til billedsekvensen er slut. Slutsekvenser måler antallet af sorte-pixels og igen over en vis pct. del ...
Jeg har efter at have læst indlæggene ovenfor erkendt at denne metode hører fortiden til, så hvis nogen kunne hjælpe mig med ideer (og endnu bedre kodeeksempler ), er der point til vedkommende.
kristian: vil da gerne komme med et bud på en motion detector hvis det er...
kroning: jeg ville egentlig gerne se det billede du bruger som forsøg. Har du overvejet at filtrere billedet først ? ved for eksempel at øge kontrasten mindskes de små forskelle, og kan måske hjælpe med dit problem.
1000 tak for tilbuddet, som jeg med glæde siger JA-tak til.
Men det er mere end "blot" en bevægelses-detector // motion-detector (eller er det ?? - Jeg ved det ikke ..)
Jeg har 8 store tapes BetaMax (12o minutter) og en super-prof. Sony Beta-spille (med et RS485 interface). Jeg kan kontrollere Beta-spillen på alle leder og kanter via et Delphi interface-program, (primært via COM1 porten) så jeg kan vise enkeltframes, spole frem / tilbage til frame HH:MM:SS:FF - det eneste jeg ikke kan er programmeringsmæssigt at finde ud af hvor de enkelte billedsekvenser (læs "video-film") starter i HH:MM:SS:FF-format og der har jeg brug for denne motion-detector.
Jeg har en USB enhed (framegrabber) som konverterer video-signalet (RGB--> USB) så jeg kan få det ind på PC'en, som video. Her vises det på et PANEL (som er en del af ovennævnte program styring). Tidsvisningen i HH.MM.SS.FF er interrupt styret, for at sikre korrekt tidsvisning. (Meget kort fortalt)..
Det jeg ønsker er en Motion-detector, men også en detector som kan detectere END OF MOVIE (EOM). Det sker når flere FRAMES (typisk 1-5 minutter) er totalt sorte.
ok, jeg tror det er bedst at oprette et nyt spm til emnet. Har en motion detector med sensivitet og kan måle lysstyrke. Ved ikke om det dækker dit behov, men ellers kan du måske bygge lidt om på det. Skal dog lige bruge lidt tid på at oversætte det til bitmap..
Jeg har lavet en løsning der ser ud til at virke fint (det er muligvis noget fusk). Jeg tager gennemsnittet af farverne på 5 pixel og sammenligner det med gennemsnittet af de næste 5 pixel og hvis forskellen er mere end 30% så har jeg fundet starten. Jeg springer 50 pixel for hver scanning aht. hastighed.
Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.