Các phương pháp truy xuất pixel dùng OpenCV
Ảnh được cấu tạo bởi các pixel, điểm ảnh, chính vì lẽ đó mà có thể nói xử lý ảnh là quá trình xử lý trên điểm ảnh. Làm sao để làm việc một cách hiệu quả, truy xuất, cập nhật nhanh nhất, thuận tiện nhất các giá trị này là vấn đề căn cơ cần phải học khi nhập môn.
Giả sử bạn cần truy xuất vào kênh màu thứ K của điểm ảnh ở dòng i và cột thứ j. Chỉ mục i của dòng thuộc vào khoảng [0, height - 1]. Chỉ mục j của cột nằm trong đoạn [0, width-1]. Chỉ mục K của kênh màu thì giới hạn trong [0, nchannels - 1].Tôi đưa ra các thông tin khoảng chạy này với ngụ ý nếu bạn sử dụng các phương pháp dưới đây trong vòng lặp thích hợp bạn có thể duyệt toàn các điểm trong ảnh.
Giả sử bạn cần truy xuất vào kênh màu thứ K của điểm ảnh ở dòng i và cột thứ j. Chỉ mục i của dòng thuộc vào khoảng [0, height - 1]. Chỉ mục j của cột nằm trong đoạn [0, width-1]. Chỉ mục K của kênh màu thì giới hạn trong [0, nchannels - 1].Tôi đưa ra các thông tin khoảng chạy này với ngụ ý nếu bạn sử dụng các phương pháp dưới đây trong vòng lặp thích hợp bạn có thể duyệt toàn các điểm trong ảnh.
- Phương pháp truy xuất gián tiếp (Indirect access): (đánh giá: thông dụng, không hiệu quả, truy xuất đến bất kì định dạng nào được hỗ trợ bởi OpenCV)
- Dùng cho hình chỉ có 1byte / 1 kênh màu (single-channel byte image):
IplImage* img=cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,1); CvScalar s; s=cvGet2D(img,i,j); // get the (i,j) pixel value printf("intensity=%f\n",s.val[0]); s.val[0]=111; cvSet2D(img,i,j,s); // set the (i,j) pixel value
- Dùng cho hình đa kênh với mỗi kênh là 1 byte hay 1 float (multi-channel float (or byte) image):
IplImage* img=cvCreateImage(cvSize(640,480),IPL_DEPTH_32F,3); CvScalar s; s=cvGet2D(img,i,j); // get the (i,j) pixel value printf("B=%f, G=%f, R=%f\n",s.val[0],s.val[1],s.val[2]); s.val[0]=111; s.val[1]=111; s.val[2]=111; cvSet2D(img,i,j,s); // set the (i,j) pixel value
- Dùng cho hình chỉ có 1byte / 1 kênh màu (single-channel byte image):
- Truy xuất trực tiếp: (Hiệu quả, dễ tìm ẩn lỗi)
- Dùng cho single-channel byte image:
IplImage* img=cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,1); ((uchar *)(img->imageData + i*img->widthStep))[j]=111;
- Dùng cho multi-channel byte image:
IplImage* img=cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,3); ((uchar *)(img->imageData + i*img->widthStep))[j*img->nChannels + 0]=111; // B ((uchar *)(img->imageData + i*img->widthStep))[j*img->nChannels + 1]=112; // G ((uchar *)(img->imageData + i*img->widthStep))[j*img->nChannels + 2]=113; // R
- Dùng cho multi-channel float image:
IplImage* img=cvCreateImage(cvSize(640,480),IPL_DEPTH_32F,3); ((float *)(img->imageData + i*img->widthStep))[j*img->nChannels + 0]=111; // B ((float *)(img->imageData + i*img->widthStep))[j*img->nChannels + 1]=112; // G ((float *)(img->imageData + i*img->widthStep))[j*img->nChannels + 2]=113; // R
- Dùng cho single-channel byte image:
- Truy xuất trực tiếp sử dụng pointer: (Đơn giản, hiệu quả)
- Dùng cho single-channel byte image:
IplImage* img = cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,1); int height = img->height; int width = img->width; int step = img->widthStep/sizeof(uchar); uchar* data = (uchar *)img->imageData; data[i*step+j] = 111;
- Dùng cho multi-channel byte image:
IplImage* img = cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,3); int height = img->height; int width = img->width; int step = img->widthStep/sizeof(uchar); int channels = img->nChannels; uchar* data = (uchar *)img->imageData; data[i*step+j*channels+k] = 111;
- Dùng cho multi-channel float image (assuming a 4-byte alignment):
IplImage* img = cvCreateImage(cvSize(640,480),IPL_DEPTH_32F,3); int height = img->height; int width = img->width; int step = img->widthStep/sizeof(float); int channels = img->nChannels; float * data = (float *)img->imageData; data[i*step+j*channels+k] = 111;
- Dùng cho single-channel byte image:
- Truy xuất trực tiếp dùng c++ wrapper: (Đơn giản và truy xuất hiệu quả)
- Định nghĩa a c++ wrapper cho single-channel byte images, multi-channel byte images, and multi-channel float images:
template 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 RgbImage; typedef Image RgbImageFloat; typedef Image BwImage; typedef Image BwImageFloat;
- Đối với single-channel byte image:
IplImage* img=cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,1); BwImage imgA(img); imgA[i][j] = 111;
- Đối với multi-channel byte image:
IplImage* img=cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,3); RgbImage imgA(img); imgA[i][j].b = 111; imgA[i][j].g = 111; imgA[i][j].r = 111;
- Đối với multi-channel float image:
IplImage* img=cvCreateImage(cvSize(640,480),IPL_DEPTH_32F,3); RgbImageFloat imgA(img); imgA[i][j].b = 111; imgA[i][j].g = 111; imgA[i][j].r = 111;
- Định nghĩa a c++ wrapper cho single-channel byte images, multi-channel byte images, and multi-channel float images:
- BONUS: Ứng dụng phương pháp truy xuất để duyệt image data
void VnPPixelAccess(IplImage *image) {
int nl= image->height; // number of lines
int nc= image->width * image->nChannels; // total number of element per line
int step= image->widthStep; // effective width
// get the pointer to the image buffer
unsigned char *data= reinterpret_cast (image->imageData);
for (int i=0; i < nl; i++) {
for (int j=0; j < nc; j += nChannels) {
// process each pixel ---------------------
for(int k=0; k < image->nChannels; k++) {
data[j + k]= giá trị mà bạn muốn :p;
}
// end of pixel processing ----------------
} // end of line
data+= step; // next line
}
}
Binh Nguyen - Bioz
Các phương pháp truy xuất pixel dùng OpenCV
Reviewed by Bioz Nguyen
on
8:11:00 AM
Rating: