Per la vostra immagine di origine
lo farei:
creare maschera di roba marrone
Basta soglia H,S
e ignorare V
, Hai già presente. Uso il numero intero 255
anziché il colore (Blue) per il calcolo finale.
sfocatura maschera
Questo rimuove piccoli gruppi di parti selezionate erroneamente.Dopodiché dovresti ritagliare nuovamente la maschera perché il valore della maschera sarà un po 'più piccolo di 255
a meno che tu non abbia aree completamente selezionate. Più grande è l'area, maggiore è il valore (più vicino a 255
). I soglia con >=150
scansione della maschera da linee orizzontali
per ciascuna linea trovare il centro di gravità di tutti i pixel selezionati
Dopo sfocatura e tresholding nuovamente la maschera utilizzata è Aqua. Calcola quindi la coordinata del punto medio x
di tutti i pixel mascherati in ogni riga. Questo punto è contrassegnato con White.
linea di regresso attraverso tutti i centri di gravità
Io uso il mio approximation search per questo, ma è possibile utilizzare qualsiasi regressione che si vuole. La linea regredito è contrassegnata con Red
ho usato l'equazione linea x=x0+y*dx
dove y=<0,pic1.ys>
. E cercare la soluzione su intervalli:
x0=<-pic1.xs,+2*pic1.xs>
dx=<-10,+10>
Dove pic1.xs,pic1.ys
è la risoluzione dell'immagine. Quindi, come puoi vedere, non copro tutti gli angoli, ma penso che non funzionerebbe comunque su questi casi limite (vicino alle direzioni orizzontali). In questi casi, dovresti farlo sulle linee verticali e usare invece x=y0+x*dy
.
Qui C++ fonte ho fatto questo con:
picture pic0,pic1;
// pic0 - source img
// pic1 - output img
int x,y,h,s,v,px,pn,*p;
color c;
// copy source image to output
pic1=pic0;
pic1.save("cornbot0.png");
// create brown stuff mask
for (y=0;y<pic1.ys;y++) // scan all H lines
for (x=0;x<pic1.xs;x++) // scan actual H line
{
c=pic1.p[y][x]; // get pixel color
rgb2hsv(c); // in HSV
h=WORD(c.db[picture::_h]);
s=WORD(c.db[picture::_s]);
v=WORD(c.db[picture::_v]);
// Treshold brownish stuff
if ((abs(h- 20)<10)&&(abs(s-200)<50)) c.dd=255; else c.dd=0;
pic1.p[y][x]=c;
}
pic1.save("cornbot1.png");
pic1.smooth(10); // blur a bit to remove small clusters as marked
pic1.save("cornbot2.png");
// compute centers of gravity
p=new int[pic1.ys]; // make space for points
for (y=0;y<pic1.ys;y++) // scan all H lines
{
px=0; pn=0; // init center of gravity (avg point) variables
for (x=0;x<pic1.xs;x++) // scan actual H line
if (pic1.p[y][x].dd>=150) // use marked points only
{
px+=x; pn++; // add it to avg point
pic1.p[y][x].dd=0x00004080; // mark used points (after smooth) with Aqua
}
if (pn) // finish avg point computation
{
px/=pn;
pic1.p[y][px].dd=0x00FFFFFF;// mark it by White
p[y]=px; // store result for line regression
} else p[y]=-1; // uncomputed value
}
// regress line
approx x0,dx;
double ee;
for (x0.init(-pic1.xs,pic1.xs<<1,100,3,&ee); !x0.done; x0.step()) // search x0
for (dx.init(-10.0 ,+10.0 ,1.0,3,&ee); !dx.done; dx.step()) // search dx
for (ee=0.0,y=0;y<pic1.ys;y++) // compute actua solution distance to dataset
if (p[y]!=-1) // ignore uncomputed values (no brown stuff)
ee+=fabs(double(p[y])-x0.a-(double(y)*dx.a));
// render regressed line with Red
for (y=0;y<pic1.ys;y++)
{
x=double(x0.aa+(double(y)*dx.aa));
if ((x>=0)&&(x<pic1.xs))
pic1.p[y][x].dd=0x00FF0000;
}
pic1.save("cornbot2.png");
delete[] p;
io uso il mio picture
classe per le immagini in modo da alcuni membri sono:
xs,ys
dimensioni immagine in pixel
p[y][x].dd
è pixel alla (x,y)
posizione di 32 bit tipo intero
p[y][x].dw[2]
è pixel alla (x,y)
posizione 2x16 bit tipo integer per 2D campi
p[y][x].db[4]
è pixel alla (x,y)
posizione del tipo di bit 4x8 intero per un facile accesso al canale
clear(color)
- cancella intera immagine
resize(xs,ys)
- ridimensiona un'immagine per nuova risoluzione
bmp
- VCL incapsulato GDI bitmap con accesso Canvas
smooth(n)
- veloce sfocatura dell'immagine n
volte
È possibile migliorare ulteriormente questo con la segmentazione (rimozione di piccoli gruppi) sulla base di area e la posizione. Inoltre puoi ignorare i picchi troppo alti nei punti AVG tra vicini. Inoltre è possibile rilevare il cielo e ignorare l'intera area in cui è presente il cielo.
[edit1] liscio
Questo è come il mio aspetto liscio come:
void picture::smooth(int n)
{
color *q0,*q1;
int x,y,i,c0[4],c1[4],c2[4];
bool _signed;
if ((xs<2)||(ys<2)) return;
for (;n>0;n--)
{
#define loop_beg for (y=0;y<ys-1;y++){ q0=p[y]; q1=p[y+1]; for (x=0;x<xs-1;x++) { dec_color(c0,q0[x],pf); dec_color(c1,q0[x+1],pf); dec_color(c2,q1[x],pf);
#define loop_end enc_color(c0,q0[x ],pf); }}
if (pf==_pf_rgba) loop_beg for (i=0;i<4;i++) { c0[i]=(c0[i]+c0[i]+c1[i]+c2[i])>>2; clamp_u8(c0[i]); } loop_end
if (pf==_pf_s ) loop_beg { c0[0]=(c0[0]+c0[0]+c1[0]+c2[0])/ 4; clamp_s32(c0[0]); } loop_end
if (pf==_pf_u ) loop_beg { c0[0]=(c0[0]+c0[0]+c1[0]+c2[0])>>2; clamp_u32(c0[0]); } loop_end
if (pf==_pf_ss ) loop_beg for (i=0;i<2;i++) { c0[i]=(c0[i]+c0[i]+c1[i]+c2[i])/ 4; clamp_s16(c0[i]); } loop_end
if (pf==_pf_uu ) loop_beg for (i=0;i<2;i++) { c0[i]=(c0[i]+c0[i]+c1[i]+c2[i])>>2; clamp_u16(c0[i]); } loop_end
#undef loop_beg
#define loop_beg for (y=ys-1;y>0;y--){ q0=p[y]; q1=p[y-1]; for (x=xs-1;x>0;x--) { dec_color(c0,q0[x],pf); dec_color(c1,q0[x-1],pf); dec_color(c2,q1[x],pf);
if (pf==_pf_rgba) loop_beg for (i=0;i<4;i++) { c0[i]=(c0[i]+c0[i]+c1[i]+c2[i])>>2; clamp_u8(c0[i]); } loop_end
if (pf==_pf_s ) loop_beg { c0[0]=(c0[0]+c0[0]+c1[0]+c2[0])/ 4; clamp_s32(c0[0]); } loop_end
if (pf==_pf_u ) loop_beg { c0[0]=(c0[0]+c0[0]+c1[0]+c2[0])>>2; clamp_u32(c0[0]); } loop_end
if (pf==_pf_ss ) loop_beg for (i=0;i<2;i++) { c0[i]=(c0[i]+c0[i]+c1[i]+c2[i])/ 4; clamp_s16(c0[i]); } loop_end
if (pf==_pf_uu ) loop_beg for (i=0;i<2;i++) { c0[i]=(c0[i]+c0[i]+c1[i]+c2[i])>>2; clamp_u16(c0[i]); } loop_end
#undef loop_beg
#undef loop_end
}
}
Semplicemente peso medio 3 pixel
(x,y)=(2*(x,y)+(x-1,y)+(x,y-1))/4
e dopo che fanno lo stesso con
(x,y)=(2*(x,y)+(x+1,y)+(x,y+1))/4
per evitare lo spostamento dell'immagine. Quindi tutta questa faccenda è ripetuta n
volte e questo è tutto. Puoi ignorare la pinza e le opzioni in formato pixel in questo caso è pf==_pf_rgba
ma usa comunque solo un canale ...dec_color,enc_color
è sufficiente decomprimere, raggruppare i canali di colore in/da array di variabili per evitare problemi di troncamento e overflow su canali a 8 bit e anche per formattare/semplificare il codice un po 'meglio (per supporto di diversi formati pixel)
btw base liscia è il stessa di convoluzione con
0.00 0.25 0.00
0.25 0.50 0.00
0.00 0.00 0.00
e
0.00 0.00 0.00
0.00 0.50 0.25
0.00 0.25 0.00
vorrei prendere in considerazione le domande che non hanno una precisa formulazione (molte utili "visione/apprendimento" problemi simili) troppo ampia. Vorrei che ci fosse un altro sito di rete dedicato a loro, ma non riesco a trovarne uno. –
un filtro mediano di dimensioni discrete, come 9x9 dovrebbe sbarazzarsi della maggior parte delle cose. potresti anche provare a combinare i filtri massimo e minimo. – Piglet
@Piglet Grazie. Applico il filtro mediano come suggerimento per liberarmi di piccole particelle. Vedi il post modificato. –