Avatar billede kroning Nybegynder
18. februar 2012 - 19:17 Der 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.
Avatar billede mbsnet Nybegynder
18. februar 2012 - 23:08 #1
Lavede noget lignende for få dage siden, til et andet billede format. Har oversat det til brug med TBitmap:

unit Unit1;

interface

uses
  Windows, Classes, Graphics, Controls, Forms, ExtCtrls, jpeg;

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;

jpg.loadFromFile('C:\billede.jpg');
bmp.assign(jpg);
bmp.pixelFormat:=pf24bit;

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;

image1.picture.bitmap:=bmp;
end;

end.
Avatar billede kroning Nybegynder
19. februar 2012 - 16:21 #2
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.
Avatar billede mbsnet Nybegynder
19. februar 2012 - 19:24 #3
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.
Avatar billede mbsnet Nybegynder
19. februar 2012 - 19:26 #4
btw, den scanner først top indtil den finder en forskel.
derefter de andre kanter, for til sidst at gentage processen i få tilfælde...
19. februar 2012 - 20:23 #5
Hej,

Jeg er med på en diskret sidelinie.

Mit problem:

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.

Tak på forkant

Kristian
Avatar billede mbsnet Nybegynder
20. februar 2012 - 18:49 #6
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.
20. februar 2012 - 19:23 #7
HEJ MBSNET,

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.

Kristian
Avatar billede mbsnet Nybegynder
20. februar 2012 - 20:17 #8
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..
Avatar billede kroning Nybegynder
20. februar 2012 - 20:34 #9
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.
Avatar billede mbsnet Nybegynder
20. februar 2012 - 20:51 #10
ok godt du fandt en løsning. kan høre at hvis du springer 50 px vil det ikke virke på et 16x16 ikon :-)
20. februar 2012 - 20:56 #11
HEJ MSBNET,

Tak for responsen.

Jeg åbner problemet i et nyt spørgsmål i Delphi gruppen.

Men 10000000 tak for din hjælp hidtil.

KRistian
Avatar billede kroning Nybegynder
20. februar 2012 - 21:00 #12
Billederne er altid mindst 1280x720. Smider du et svar.
Avatar billede mbsnet Nybegynder
21. februar 2012 - 18:34 #13
kroning: springer over denne gang :)
Avatar billede kroning Nybegynder
29. februar 2012 - 00:36 #14
Så svarer jeg selv.
Avatar billede Ny bruger Nybegynder

Din løsning...

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.

Loading billede Opret Preview
Kategori
Kurser inden for grundlæggende programmering

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester