PDA

View Full Version : [c++] che vuol dire questa istruzione?


vermaccio
29-03-2006, 18:53
in cima al listato, insomma nel blocco iniziale dove si definiscono le variabili etc etc c'è questo. che vuol dire?

#define BALL(R, G, B) (R >= 250 && G < 20 && B < 5)?TRUE:FALSE

che vuol dire?


e in seguito nel "main" c'è l'istruzione

if (BALL(R(P),G(P),B(P))) {...blablabla...
}

quando è che l'if attiva il "blablabla" e quando no?

shinya
30-03-2006, 08:13
E' una macro, che in C++ è consigliabile sostituire con una funzione inline.
Nel caso specifico, se R >= 250 && G < 20 && B < 5 ritorna true, altrimenti false.
Mi pare piuttosto intuitivo...

vermaccio
30-03-2006, 08:40
<<E' una macro>>
:)
questo volevo sapere, altrimenti non avevo idea di cosa cercare nel manualone c++.

comunque:
invece della macro non bastava scrivere SOLO dentro l'if

if (R >= 250 && G < 20 && B < 5)) {...blablabla...

???

BALL(R(P),G(P),B(P)) è a sua volta una macro perchè definita

#define R(P) *(P)
#define G(P) *(P+1)
#define B(P) *(P+2)

quindi in realtà dovrei porre

if (*(P) >= 250 && *(P+1)< 20 && *(P+2) < 5)) {...blablabla...

cionci
30-03-2006, 08:58
Per la leggibilità a volte sono davvero utili ;)

sottovento
30-03-2006, 09:02
Per la leggibilità a volte sono davvero utili ;)
Vero. Purtroppo spesso sono un'arma a doppio taglio, possono produrre effetti collaterali non indifferenti.

E poi, se ben usate, possono tornare utili per ottimizzare i tempi di esecuzione. Se usate male, invece, possono anche peggiorare le prestazioni.

In tutta sincerita', ho un sano terrore delle macro. Le uso con estrema cautela...

vermaccio
30-03-2006, 09:18
questo è un listato che m hanno dato da usare come "base" per capire come funziona un robot che, comandato tramite c++, trova una palla rossa tramite videocamera e ci si dirige.

guardate che intrico di macro: una che richiama l'altra....
se c'è un errorre non lo troverai mai!!!!!!
mi tocca riscriverlo in chiaro!!!!!!!



//esempio ricerca palla rossa

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <device/robot.h>
#include <device/differential_wheels.h>
#include <device/receiver.h>
#include <device/distance_sensor.h>

#include <device/camera.h>

#define MILLISECONDI 32

//Global variables
static int width, height;
unsigned char *image;
static int speed;
unsigned char *P;
static float f;
static DeviceTag camera;

//Define Colors
#define TRUE 1
#define FALSE 0
#define BALL(R, G, B) (R >= 250 && G < 20 && B < 5)?TRUE:FALSE

//Image processing procedures
#define get_pixel(image, x, y) image+3*(x+y*width)
#define set_pixel(image, x, y, z) image[3*(x+y*width)] = z
#define R(P) *(P) //puntatore a indirizzo P
#define G(P) *(P+1) //puntatore a indirizzo P + 1 cella di puntatore: ovvero la cella dopo
#define B(P) *(P+2) //puntatore a indirizzo P + 2 celle di puntatorio: ovvero due celle dopo






//XXXXXXXXXXXXXXXXXX
static void reset(void)
{
camera = robot_get_device("camera");
camera_enable(camera, MILLISECONDI);
width = camera_get_width(camera);
height = camera_get_height(camera);

// printf("reset done\n");
}

static int run(int ms)
{
short left_speed, right_speed;
int i, j;

image = (unsigned char *)camera_get_image(camera);

left_speed = -20; //gira su se stesso finchè non trova la palla...
right_speed = 20;

//algoritmo ricerca palla
for (j=0; j < height; j++) {
for (i=width/2-5; i < width/2+5; i++) {
P = get_pixel(image, i, j);
//ball
if (BALL(R(P),G(P),B(P))) {
//printf("I see the red ball\n");
left_speed = 50; //... ha trovato la palla e va verso la palla
right_speed = 50;
goto next1; //break;
}
}
}


next1: //finisci qui con il "goto"

differential_wheels_set_speed(left_speed, right_speed);

return MILLISECONDI;
}


//XXXXXXXXXXXXXXXXXX
int main()
{
robot_live(reset);
robot_run(run);
return 0;
}

cionci
30-03-2006, 09:26
Non mi sembra che ci sia una grande confusione... Metti setPixel e getPixel come funzioni...

vermaccio
30-03-2006, 09:35
appunto!

quello è solo uno stralcio minimo del resto dei listati.
non hai idea del casino che c'è.

ci sono punti con una dozzina di define che si richiamano lìun l'altro e poi nel listato vengono infilati quà e là.

modificare il listato è impossibile.

scritto così è <<immodificabile>>

tocca estrapolare le functions!

che noia......

sottovento
30-03-2006, 09:46
Ciao,
se posso permettermi un consiglio, ti suggerei di eliminare il goto.
Invece di:



... omissis ...

static int run(int ms)
{
... omissis ...
//algoritmo ricerca palla
for (j=0; j < height; j++) {
for (i=width/2-5; i < width/2+5; i++) {
P = get_pixel(image, i, j);
//ball
if (BALL(R(P),G(P),B(P))) {
//printf("I see the red ball\n");
left_speed = 50; //... ha trovato la palla e va verso la palla
right_speed = 50;
goto next1; //break;
}
}
}


next1: //finisci qui con il "goto"

... omissis...



puoi fare:



... omissis ...

static int run(int ms)
{
BOOL found = FALSE;

... omissis ...
//algoritmo ricerca palla
for (j=0; j < height && !found; j++) {
for (i=width/2-5; (i < width/2+5) && !found; i++) {
P = get_pixel(image, i, j);
//ball
if ((found = BALL(R(P),G(P),B(P)))) {
//printf("I see the red ball\n");
left_speed = 50; //... ha trovato la palla e va verso la palla
right_speed = 50;

//break;
}
}
}


// Al termine del ciclo, il flusso di esecuzione sara' qui.
// Se found == FALSE non hai trovato la passa, altrimenti l'hai trovata


... omissis...



C'e' anche un altro problemino nel codice originale: al termine del ciclo non hai informazioni sul fatto che la palla sia stata trovata o meno (a meno di non controllare se la speed e' cambiata).

Infine una curiosita': il codice si basa sul fatto di aver trovato un solo punto rosso al centro dell'immagine. Non e' poco per stabilire di aver trovato la palla?

Scusa se sono stato un po' invadente

High Flying
Sottovento

vermaccio
30-03-2006, 09:52
C'e' anche un altro problemino nel codice originale: al termine del ciclo non hai informazioni sul fatto che la palla sia stata trovata o meno (a meno di non controllare se la speed e' cambiata).

questa non l'ho capita. intendi dire che se non trova la palla (es: la palla non esiste proprio come caso limite) lui continua all'infinito a girare senza fermarsi MAI?


Infine una curiosita': il codice si basa sul fatto di aver trovato un solo punto rosso al centro dell'immagine. Non e' poco per stabilire di aver trovato la palla?

perchè al centro dell'immagine? non esce dal ciclo if appena vede un punto rosso anche al bordo immagine?


Scusa se sono stato un po' invadente
High Flying
Sottovento

ma che invadente! ben venga! sto smadonnando su questo listato scritto da un cane!!!! ha bug ovunque!

sottovento
30-03-2006, 10:09
questa non l'ho capita. intendi dire che se non trova la palla (es: la palla non esiste proprio come caso limite) lui continua all'infinito a girare senza fermarsi MAI?

Se non trova la palla, i due cicli for innestati verranno completati e l'esecuzione passera' al codice che segue l'etichetta del goto.
Verra' pertanto effettuata la
differential_wheels_set_speed(left_speed, right_speed);
con i valori (non cambiati) di left_speed e right_speed.
Non so dirti di piu': ti posso solo dire che, differenza di speed a parte, da quel punto in poi l'esecuzione non terra' conto del fatto che la palla sia stata trovata o meno.


perchè al centro dell'immagine? non esce dal ciclo if appena vede un punto rosso anche al bordo immagine?


Il secondo ciclo e':

for (i=width/2-5; i < width/2+5; i++)
....

dove width sembra inizializzato alla dimensione dell'immagine presa dalla camera.
Il ciclo esterno, invece, va da 0 a height (sarebbe height -1 ma non ha importanza).
Pertanto il tuo robot analizza una striscia verticale di 10 pixel al centro dell'immagine raccolta.

Ripeto ancora la mia perplessita': un solo pixel non e' troppo poco? Probabilmente l'ambiente in cui il robot e' messo sara' stato attrezzato per facilitare il compito, cmq mi sembra un po' rischioso... non dico di implementare degli algoritmi di pattern matching (anche se sarei pronto a scommettere che li trovi gia' pronti su Internet), pero' magari sarebbe opportuno verificare che ci sia un gruppo di pixel adiacenti, che siano rossi...


ma che invadente! ben venga! sto smadonnando su questo listato scritto da un cane!!!! ha bug ovunque!

Beh, cerca di vedere i lati positivi. Mettere le mani nel codice altrui non e' mai facile, ma ti permette di imparare tantissimo, dagli errori e dalle soluzioni trovate (che spesso sono geniali).

E poi... un giorno qualcuno mettera' mano al tuo codice, no?

High Flying
Sottovento

vermaccio
30-03-2006, 10:12
non dico di implementare degli algoritmi di pattern matching (anche se sarei pronto a scommettere che li trovi gia' pronti su Internet),

cosa sono? e dove li trovo?


pero' magari sarebbe opportuno verificare che ci sia un gruppo di pixel adiacenti, che siano rossi...


come potrei fare per adottare questa soluzione? una volta trovato un puntino analizzo se attono che ne sono altri facendo un "cerchio" di pixel attorno al pixel trovato?

sottovento
30-03-2006, 11:23
cosa sono? e dove li trovo?


Probabilmente su Internet trovi qualcosa. Sono passati parecchi anni dalla laurea, e molti di piu' dall'esame di elaborazione delle immagini, per cui non mi ricordo tantissimo.
Devo avere ancora i libri, cerco i titoli (mi ricordo un "digital image processing", forse qualcuno nel forum ha informazioni piu' aggiornate).
Comunque se cerchi qualcosa tipo "image analysis pattern matching" dovresti trovare un bel po' di roba, probabilmente gia' pronta per l'uso.


come potrei fare per adottare questa soluzione? una volta trovato un puntino analizzo se attono che ne sono altri facendo un "cerchio" di pixel attorno al pixel trovato?

Puoi cercare di implementare un algoritmo piuttosto famoso, basato sulle adiacenze. Una volta applicato questo algoritmo (che e' abbastanza veloce per una scansione on line), puoi calcolare facilmente l'area degli oggetti in esame (espressa in pixel) e prendere opportuni provvedimenti.

Innanzitutto: puoi vedere la tua immagine come se fosse binaria: la tua macro BALL() te la "binarizza", nel senso che un pixel rispetta la condizione, oppure no.
Questa condizione e' importante per questo passaggio.

Mi e' capitato di dover implementare questo algoritmo, per cui ne conosco i dettagli. La spiegazione e' semplice ma un po' lunga, per cui non posso fornirtela ora.
Fai prima una ricerca su Internet, se non trovi nulla, allora posto l'algoritmo (magari stasera)

High Flying
Sottovento

sottovento
30-03-2006, 15:31
Ciao,
hai trovato qualcosa che fa al caso tuo?

Ad ogni modo, l'algoritmo piu' facile e' questo:
- Abbiamo gia' premesso che l'immagine e' praticamente "binaria" (ho sufficiente rosso oppure no).

Ora possiamo provare ad estrarre degli oggetti (la palla):

inizializza "count" a 1; (non 0, mi raccomando)

1 - prepariamo una nuova immagine/matrice che conterra' gli oggetti che vuoi estrarre. Questa matrice e' inizializzata a tutti zero;

2 - scandisci l'immagine di partenza da sx a dx, dall'alto in basso (due cicli for annidati);
3 - per ogni punto:
3.1 - se BALL() e' FALSE, allora non fai alcuna operazione (nella nuova matrice rimane il punto di tali coordinate a zero);
3.2 - se BALL() e' TRUE, allora controlla il punto immediatamente a sinistra e sopra (se esistono. Se non esistono, e' come se fosse zero).
3.2.1 - Se i punti controllati sono entrambi a zero, allora nella nuova matrice, nella posizione di tale pixel, ci metti il valore di "count". Incrementi poi "count";
3.2.2 - Se uno dei punti controllati ha valore diverso da zero, allora puoi copiare detto valore anche per questo pixel.
3.2.3 - Se entrambi hanno valore diverso da zero, puoi scegliere quale valore copiare. Dovrai pero' salvare in una struttura a parte (una lista) entrambi i valori (tradotto in italiano significa: mi rendo conto che i due valori rappresentano lo stesso oggetto. Potremmo parlare di relazione di equivalenza, in cui il numero e' rappresentante della classe di equivalenza stessa).

Una volta finita questa scansione, avrai una nuova matrice dove, nelle aree potenzialmente interessate dalla presenza di un oggetto rosso, si accumulano delle caselle con dei numeri.

L'ultima passata la fai su questa nuova matrice, scegliendo un numero dalla tua relazione di equivalenza (l'hai creata con la lista): se, per esempio hai stabilito che le caselle marcate con "1" e quelle marcate con "10" sono equivalenti, farai la sostituzione, per esempio, di tutte le caselle "10" col valore "1".
Questo ti permette di individuare, per esempio, anche gli oggetti concavi: per esempio, una "U", scandendo da sx a dx e dall'alto verso il basso, avrebbe numeri diversi per la prima e la seconda asta. Quando arrivi a "chiudere" la figura, ti accorgeresti dell'equivalenza. Con la sostituzione, hai che tutti i punti della "U" hanno un numero solo.

E cosi'...hai un'immagine in cui tutti gli oggetti sono distinti, ed ognuno e' individuato mediante un unico numero.
Puoi farci ora tante belle operazioni: puoi, per esempio, calcolare l'area dell'oggetto "3" (ti basta contare quanti 3 ci sono, sono tutti adiacenti), puoi applicare algoritmi piu' sofisticati, ....

Nel tuo caso, controllerei semplicemente l'area ed eliminerei dalla mia attenzione tutti gli oggetti troppo piccoli.

Se ho tempo, ti codifico tutta questa cosa in C (purtroppo non ho tanto tempo, sono in partenza per una trasferta molto lunga...).

Spero di esserti stato utile

High Flying
Sottovento

vermaccio
31-03-2006, 08:34
ti ringrazio per le iddee.
oira per due settimane devo leggere io manualissimo di openCV
http://www.intel.com/technology/computing/opencv/overview.htm

appena fatto e passo alla parte applicativa magari ci risentiamo se ho problemi :)

comunque se hai algoritmi in c++ già fatti...manda pure. se vuoi ti do la mia mail.

ciao

sottovento
31-03-2006, 09:10
comunque se hai algoritmi in c++ già fatti...manda pure. se vuoi ti do la mia mail.

ciao

Appena ho un attimo, controllo nel mio "archivio". Se trovo qualcosa di tuo interesse mi faccio sicuramente vivo

High Flying
Sottovento

sottovento
31-03-2006, 09:12
ti ringrazio per le iddee.
oira per due settimane devo leggere io manualissimo di openCV
http://www.intel.com/technology/computing/opencv/overview.htm

ciao

Sono andato a vedere il sito. E' proprio interessante e fa al caso tuo.
Direi che l'algoritmo che ti ho presentato e' sicuramente implementato in quella libreria.

Buon lavoro
Sottovento

vermaccio
01-04-2006, 21:37
la settimana prossima mi inizio a leggere quel mattone del reference manual. povero me!
:D

ma senza quella libreria sarei invecchiato a scrivere le funzioni. sarebbe stato disumano.

comunque se trovi qualcosa di tuo mandamelo.
:) :)

ciao

vermaccio
02-04-2006, 09:54
ho trovato in rete un listato cpp che dovrebe effettuare il calcolo del determinante di una matrice!!!!!

domanda: l'intestazione della functiion dice
double Det(double **mtrx, int dim);

e che è "**"? *è puntatore. ma **?


eccoti allegato il listato se ti interessa.
io ancora non l'ho compilato e testato anche perchè ancora non ho capito la matrice di ingresso, visto il "**", che forma deve avere.

shinya
02-04-2006, 11:38
ho trovato in rete un listato cpp che dovrebe effettuare il calcolo del determinante di una matrice!!!!!

domanda: l'intestazione della functiion dice
double Det(double **mtrx, int dim);

e che è "**"? *è puntatore. ma **?


eccoti allegato il listato se ti interessa.
io ancora non l'ho compilato e testato anche perchè ancora non ho capito la matrice di ingresso, visto il "**", che forma deve avere.

Ti conviene tenere accanto anche un manuale del linguaggio.
Se * è "puntatore", ** è "puntatore a puntatore". La firma della funzione ti dice di passare un puntatore a puntatore di double e la dimensione. Di dimensione ce n'è una sola perchè suppongo la funzione si applichi a matrici NxN. I puntatori a puntatori sono il modo tipico di rappresentare matrici di valori in C (e volendo anche in C++, anche se...). Per darti un'idea:


double **malloc2d(int n, int m) {
int i;
double **t = malloc(n * sizeof(double*));
for (i = 0; i < n; ++i)
t[i] = malloc(m * sizeof(double));
return t;
}

vermaccio
02-04-2006, 13:41
grazie delle tue sempre sollecite risposte :)

mi studierò i puntatori.

comunuq eper ora, per applicare alla "bruta2 quella funzione, che devo passargli?

essendo la dichiarazione
<<double Det(double **mtrx, int dim); >>

se io creo
double risultato;
int dimensione;
e
richiamo la funzione come risultato=Det(???,dimensione)

al posto di "???" cosa ci devo scrivere? e prima di attivare la funzione, il "???" come deve essere stato dichiarato e "riempito"?

ciao

shinya
02-04-2006, 14:54
grazie delle tue sempre sollecite risposte :)

mi studierò i puntatori.

comunuq eper ora, per applicare alla "bruta2 quella funzione, che devo passargli?

essendo la dichiarazione
<<double Det(double **mtrx, int dim); >>

se io creo
double risultato;
int dimensione;
e
richiamo la funzione come risultato=Det(???,dimensione)

al posto di "???" cosa ci devo scrivere? e prima di attivare la funzione, il "???" come deve essere stato dichiarato e "riempito"?

ciao

Non pensare che un puntatore a puntatore si comporti in maniera differente dai puntatori semplici. La funzione che ti ho scritto si limita ad allocare spazio sufficiente per una matrice NxN (evitando un segmentation fault).
Tu devi inizializzare i valori all'interno della matrice prima di calcolarne il determinante.
Una traccia in C:


int N = 5, i, j;
double **matrix = malloc2d(N, N);
double det = 0;

for (i = 0; i < N; ++i)
for (j = 0; j < N; ++j)
matrix[i][j] = 1; /* riempi la matrice di 1 */

det = Det(matrix, N); /* calcola il determinante qui */


Questo giusto per darti un'idea.

Altra cosa: assicurati che la funzione che calcola il determinante utilizzi un metodo numerico efficiente per farlo, altrimenti ci metti anni (letteralmente) a vedere un risultato con matrici di dimensioni elevate.

Se vuoi approfondire cerca Numerical Recipes in C su google.