2009-10-14 4 views
3

J'ai besoin d'aide C++/pointeur. Lorsque je crée un RGB IplImage et je veux accéder à i, j-je utiliser la classe C++ suivante tirée de: http://www.cs.iit.edu/~agam/cs512/lect-notes/opencv-intro/opencv-intro.htmlConvertir IGBImage RGB en 3 tableaux

template<class T> class Image 
{ 
private: 
    IplImage* imgp; 

public: 
    Image(IplImage* img=0) {imgp=img;} 
    ~Image(){imgp=0;} 
    void operator=(IplImage* img) {imgp=img;} 
    inline T* operator[](const int rowIndx) { 
     return ((T *)(imgp->imageData + rowIndx*imgp->widthStep));} 
}; 

typedef struct{ 
    unsigned char b,g,r; 
} RgbPixel; 

typedef struct{ 
    float b,g,r; 
} RgbPixelFloat; 

typedef Image<RgbPixel>  RgbImage; 
typedef Image<RgbPixelFloat> RgbImageFloat; 
typedef Image<unsigned char> BwImage; 
typedef Image<float>   BwImageFloat; 

Je travaille avec CUDA donc parfois je dois mettre toutes les données dans un tableau , J'aime garder chaque canal dans son propre tableau, semble plus facile à gérer les données de cette façon. Je voudrais donc généralement faire quelque chose comme ceci:

IplImage *image = cvLoadImage("whatever.tif"); 
RgbImageFloat img(image); 
for(int i = 0; i < exrIn->height; i++) 
{ 
    for(int j = 0; j < exrIn->width; j++) 
    { 
     hostr[j*data->height+i] = img[i][j].r; 
     hostg[j*data->height+i] = img[i][j].g; 
     hostb[j*data->height+i] = img[i][j].b; 
    } 
} 

Je puis copier mes données à l'appareil, faire des choses avec lui, faites-le à l'hôte, puis la boucle, encore une fois, à travers le réseau assignant la retourner à IplImage et sauvegarder mes résultats.

Il me semble que je suis en train de faire une boucle, il doit y avoir un moyen plus rapide de le faire avec des pointeurs, mais je suis perdu, il doit y avoir un moyen plus efficace de le faire. Est-ce que je peux simplement utiliser un pointeur pour chaque canal? J'ai essayé de faire quelque chose comme ceci mais cela n'a pas fonctionné:

float *hostr = &img[0][0].r 
float *hostg = &img[0][0].b 
float *hostb = &img[0][0].g 

Des suggestions? Merci!

EDIT: Merci à tous pour votre réponse. Peut-être que je n'étais pas très clair sur ma question. Je suis familier sur la façon d'accéder aux canaux et à leurs données. Ce qui m'intéresse, c'est d'augmenter les performances et l'efficacité de la copie complète des données de l'IplImage vers un tableau standard, plus dans le sens de ce que csl a dit jusqu'ici. Le problème que je vois est que la façon dont les données d'un IplImage sont organisées est "rgbrgbrgbrgb".

+0

Les tableaux hostr, hostg et hostb des flottants? – csl

+0

oui, toutes les données sont flottantes. Toutes les images sont EXRs (flottants 32 bits, pas de moitié) J'ai juste utilisé le code cvLoadImage() comme un exemple rapide. – rem7

Répondre

5

Tout d'abord, si vous êtes à l'aise avec C++, vous devriez envisager d'utiliser OpenCV 2.0 qui supprime différents types de données pour les images et les matrices (IplImage* et CvMat*) et utilise une structure (Mat) pour gérer les deux. En dehors de la gestion automatique de la mémoire et d'une multitude de routines utiles pour gérer les canaux, etc. et certains modèles MATLAB-esque, c'est vraiment amusant à utiliser.

Pour votre problème, vous accédez aux canaux d'un IplImage* avec Mat, comme ceci:

IplImage *image = cvLoadImage("lena.bmp"); 
Mat Lena(image); 
vector<Mat> Channels; 
split(Lena,Channels); 
namedWindow("LR",CV_WINDOW_AUTOSIZE); 
imshow("LR",Channels[0]); 
waitKey(); 

Maintenant vous avez les copies de chaque canal dans le vectorChannels.

Si vous ne voulez pas voulez utiliser OpenCV2.0 et d'extraire les canaux, notez ce qui suit. commandes OpenCV images multi-canaux de la manière suivante:

x(1,1,1) x(1,1,2) x(1,1,3) x(1,2,1) x(1,2,2) x(1,2,3) ...

x(i,j,k) = an element in row i of column j in channel k

En outre, OpenCV pads c'est des images .. il ne faut pas oublier de sauter des lignes avec widthStep qui représente ces lacunes de remplissage. Et le long de ce que csl said, augmentez votre pointeur de ligne dans la boucle externe (en utilisant widthStep) et augmentez ce pointeur pour accéder aux éléments d'une rangée.

REMARQUE:

Puisque vous utilisez maintenant 2.0, vous pouvez contourner IplImage* avec Mat Lena = imread("Lena.bmp");.

+0

Merci, j'ai téléchargé openCV 2.0 l'autre jour je n'ai pas encore eu le temps de le regarder, nous utilisons 64bit donc je vais devoir chercher à recompiler 2.0 à 64bit donc je l'ai évité: p – rem7

+0

Je pense que ça vaut le coup. Les makefiles sont assez faciles à utiliser (CMake) et le codage avec Mat et tous les nouveaux opérateurs ont rendu mon code beaucoup plus propre et plus simple. – Jacob

+0

Jacob, merci, je viens de compiler 2.0 et j'ai fait ce que vous avez suggéré. Plutôt cool. Je vais devoir regarder ce qui est nouveau ici ... y a-t-il de la documentation pour les choses C++ ou devrais-je simplement passer par les fichiers d'en-tête à la recherche de choses? – rem7

1

Il ya place pour un lot d'amélioration ici. Tellement, que vous devriez lire sur la façon dont les gens accèdent aux bitmaps.

Tout d'abord, augmentez autant que possible la localisation de la mémoire. Cela augmentera les hits du cache et les performances. Par exemple, n'utilisez pas trois tableaux séparés pour chaque canal de couleur. Stockez-les ensemble, car vous travaillerez probablement principalement sur des pixels. Deuxièmement, ne faites pas ce calcul de largeur y * pour chaque pixel. Lorsqu'il est fait dans une boucle interne, il consomme beaucoup de cycles. Enfin, si vous voulez juste une copie complète de l'image, alors vous pouvez simplement faire un memcpy(), ce qui est très rapide. Je n'ai pas pu déduire si vous avez converti des nombres flottants en entiers, mais sinon, utilisez memcpy() pour les régions qui ne se chevauchent pas.

Si vous vous demandez comment vous pouvez le faire avec des pointeurs (type de pseudo-code, et pas non testé):

float *dst = &hostg[0][0]; 
RgbPixelFloat *src = &img[0][0]; 
RgbPixelFloat *end = &img[HEIGHT][WIDTH] + 1; 

// copy green channel of whole image 
while (src != end) { 
    *dst = src->g; 
    ++dst; 
    ++src; 
} 
+0

Je ne pense pas que le cache s'applique à CUDA. Même si c'était le cas, de nombreux algorithmes d'images fonctionnent indépendamment sur les canaux, et obtiendront même une meilleure localisation s'ils n'ont pas à sauter les parties inutilisées du triplet. –

+0

L'OP veut savoir comment séparer 'img' dans les canaux' r', 'g' et' b' – Jacob

Questions connexes