Thứ tự của mô hình màu RBG trong opencv là gì
Hello
Theo mình biết trong opencv sử dụng mô hình màu RBG theo thứ tự BGR. Vấn đề là mấy tháng trước mình cũng làm 1 project có dùng opencv để hiển thị ảnh xem kết quả. Thì thứ tự màu lại khác (lúc đó mình dùng bản 3.0.0 beta). Mình đẩy dữ liệu từ array (kiểu Matrix do mình tạo ra và đọc dữ liệu vào đó) vào Mat của opencv như sau
Giờ mình cũng đang làm 1 project khác có sử dụng opencv (bản 3.2) thì dùng thứ tự như trên lại bị lỗi màu ngay và mình thử làm như thế này
khác nhau ở chỗ
pixel[0]
pixel[2]
pixel[1]
với
pixel[2]
pixel[1]
pixel[0]
thật sự không biết kênh nào là b, kênh nào là g, kênh nào là r nữa
(2 lần đẩy array qua Mat trên 1 cái sử dụng array 1d, 2 cái 2d, và cùng giải mã ảnh theo 1 kiểu, 1 ảnh 3x3, mỗi pixel có 3 kênh, thì array 2d sẽ có 3x9 phần tử, array 1d có 27 phần tử, nghĩa là thứ tự pixel giống nhau -> vấn đề là ở cái thứ tự mô hình RBG trong opencv)
vậy chốt lại
pixel[0]
pixel[1]
pixel[2]
cái nào là r, cái nào là g, cái nào là b ???
Thank you
Bạn phải từng bước kiểm tra xem nó sai ở bước nào. Từ input hay phần hiển thị.
Thứ nhật, Phải kiểm tra input của nó là gì ? Camera hay tập tin ảnh.
Với camera thì nó là BGR, có RGB thì chưa gặp bao giờ (có thể có nhưng chưa gặp).
Với file thì hên xui. Có thể người ta lưu RGB hoặc BGR.
Nếu lưu với RGB => sai ngay từ input.
Thứ hai, Kiểm tra thành phần hiển thị là thành phần nào ?
Cùng với dữ lieu BGR hay RGB thì khi sử dung các thành phần khác nhau để hiển thị ảnh thì nó sẽ nhận kênh 0 là R hoặc là B.
Ví dụ:
Với Bitmap hiển thị trên PictureBox (WinForm C#) hoặc WriteableBitmap hiển trị trên Image (WPF) thì nó hiển thị đúng.
Nhưng cũng với dữ lieu đó với QImage của QT hiển thị trên QLabel thì sẽ sai thứ tự màu. R và B sẽ đảo lộn.
=> Thực tế dữ lieu màu vẫn đúng nhưng thành phần hiển thị đã hiển thị sai.
Mà khoan, các truy cập dữ lieu màu của cậu nó hơi lạ.
Mình truy cập qua con trỏ dữ lieu image.data chứ không getRow như thế kia.
Kiểu 1D:
Kiểu 2D:
em tìm được 1 bài viết nói như thế này
và em làm theo thÌ đúng là ảnh trên đĩa là RGB, còn opencv là BGR. Vậy [0] là B, [1] là G, [2] là R
em dùng imshow() của opencv ạ, vì em không làm gui
đưa code ko đúng chỗ nên mò ko ra là đúng rồi.
bản thân thằng
cv::Mat
ko có cần biết nó chứa RGB hay BGR, nó chỉ chứa dữ liệu thế thôi. Còn thằng cần quan tâm tới BGR hay RGB là ở thằng hiện nó ra lên màn hình, ở đây làcv::imshow
gu gồ "
cv::imshow
RGB or BGR" là ra ngay câu trả lời: https://stackoverflow.com/a/16413296/2683574thêm câu trả lời ở đây, chuyển rgbMat thành bgrMat: http://answers.opencv.org/question/33948/how-do-i-capture-process-and-output-an-image-in-rgb-not-bgr/?answer=33968#post-id-33968
thêm phát nữa: nếu data đọc được từ file ảnh lên là
vector<uchar>
thì có thể chuyển lẹ như sau, khỏi cần viết vòng lặp liếc gì hết:cv::cvtColor
cv::ColorConversionCodes
nhớ xài cái namespace dùm cái, đọc vào cái code bên thớt kia thấy nào là Matrix nào là Mat, chả biết cái nào là tự định nghĩa cái nào là của opencv, khổ.
thằng opencv cũng tâm thần, đều là int flag mà chỗ thì đặt macro
CV_...
, chỗ thì xài namespacecv::...
, vãi cả thư việncái getData() là getter của lớp Matrix em viết thôi ạ, để em chuyển data của Matrix sang public
e không dùng hàm gì trong thư viện opencv trừ cái imshow để hiển thị ảnh xem kết quả
đọc ảnh em tự code, nên thứ tự sau khi giải mã ảnh khác với thứ tự của opencv chút, e sửa được rồi ạ
xài sẵn mấy hàm của thư viện người ta luôn, đừng copy thủ công chi, 1 là chậm (copy từng byte), 2 là khổ vì phải đi debug xem vòng lặp for đúng sai chỗ nào.
Vấn đề có thể nó nằm ở chỗ dữ liệu ghi xuống đĩa có đúng định dạng hay không. Dữ liệu đọc lên cũng có đúng hay không. Bởi vì opencv có nhiều định dạng. Khi lưu định dạng khác nhau đó xuống đĩa thì định dạng dưới đĩa không phải lúc nào cũng là RGB. Đọc lên cũng vậy.
data là mảng động 2d thì có dùng được kiểu đấy không anh
unsinged char **data;
em cũng thấy người ra làm thế với mảng tĩnh, hoặc mảng 1d
tiện đây anh cho em hỏi, em muốn tách 1 vùng dựa vào đặc trưng màu của nó, thì dùng mô hình màu nào cho thích hợp hả ảnh
ví dụ
e muốn tách vùng có mã thẻ ra, nếu chuyển qua ảnh xám hoặc nhị phân làm thì rất cực, có thể tân dùng cái nền màu chứa mã thẻ
Tách dựa vào màu sắc nhiều khi có độ ổn định không cao trong trường hợp các màu lân cận sai lệch không nhiều với màu đối tượng cần tách.
Nếu muốn làm theo phương pháp đó thì phân tích tỷ lệ màu R,G,B. Tức là phân tích xem vùng mã thẻ nó có R,G,B trong ngưỡng nào, bao nhiêu % rồi lọc trong cái vùng cần tách có pixel nào phù hợp thì đánh dấu lại. Sau đó còn phải tìm mật độ các điểm đánh dấu nữa vì nó sẽ có cả những điểm ngoài vùng cũng được đánh dấu. Nếu điểm ngoài vùng nhiều quá thì cũng fail
Với đề bài trên mình nghĩ bạn dung các thuật toán matching có sẵn (TemplateMatching, ShapeMatching) để tìm được2 vị trí cái sọc xanh 2 bên. Từ vị trí sọc xanh tính ra vùng mã số vì vị trí của vùng mã thẻ so với 2 sọc xanh là cố định rồi.
hình như ko @_@
mảng “động” 2 chiều
T**
dỏm lắm, xài mảng 1 chiều giả 2 chiềuT*
dễ copy hơn và copy lẹ hơn (ví dụ thông quamemcpy
lẹ hơn copy từng dòng vớiT**
rất nhiều). Nếu viết thư viện đọc file png thì nên đọc nó vào mảng 1 chiềuwidth * height
pixels luôn và trả về 1 cái struct gồmT*
và 2 intwidth
,height
. Hầu như tất cả mọi thư viện đều hỗ trợ đọc dữ liệu từ mảng 1 chiều giả 2 chiều. Nếu viết code C++ thì đừng trả vềT*
mà trả vềstd::vector<T>
.e cũng đọc vào mảng 1d mà, nhưng kết quả trả về mảng 2d, vì còn liên quan đến xử lý
C++ có cho overload cái toán tử () mà, overload nó rồi xài thoải mái như mảng 2 chiều vậy:
sao kiểu truy cập Mat của anh lạ lạ thế nhỉ
E tìm được các kiểu truy cập Mat trong opencv cũng như tốc độ của nó như sau
http://longstryder.com/2014/07/which-way-of-accessing-pixels-in-opencv-is-the-fastest/
Không có gì lạ cả. Một Mat sẽ có dữ liệu ảnh được trỏ bởi con trỏ data. Con trỏ này được public hiển nhiên truy cập qua nó hiệu suất xử lý cao nhất nhưng nó nguy hiểm. Trước kia mình hay dùng như vậy với MiplImage.
Cách truy cập qua ptr(int row) của bạn dùng thực chất là nó cũng lấy dữ liệu mà con trỏ data đang trỏ tới nhưng nó sẽ vòng vèo một chút. An toàn hơn và tất nhiên sẽ chậm hơn.
Trong link bạn đưa cũng đã nói như vậy.
Xem các member của cv::Mat và ý nghĩa của nó ở đây:
https://docs.opencv.org/3.1.0/d3/d63/classcv_1_1Mat.html
Anh có thể xem lại các truy cập mat anh viết phía trên giúp em không, có gì đó sai sai :3 Em cũng đang cần tìm cách truy cập Mat nhanh nhất, để đẩy dữ liệu vào xem thử ảnh kết quả , vì phần xử lý ảnh, cấu trúc dữ liệu lưu trữ, đọc , ghi file ảnh em tự code, nhưng mỗi phần hiển thị k biết dùng cái gì hiển thị cho trực quan mà k cần dùng mấy lib bự bự như opencv
Dấu . có thể là -> tùy vào cách bạn khai báo image là con trỏ hay không. Cái này là C++ quy định chắc là không vấn đề gì.
Code sẽ như thế này,. Chú ý là cách truy cập kiểu 2D sẽ chậm hơn 1D:
Việc hiển thị thì có thể ghi xuống file (dung hàm cv::imwrite hoặc image->save(…)).
Hiển thị lên gui thì tùy vào bạn dung cái gì.
C++.NET hoặc C# WindowsForms thì dung PictureBox hiển thị Bitmap. Sẽ copy dữ lieu ảnh vào dữ lieu của Bitmap hoặc khai báo Bitmap có con trỏ dữ lieu trùng với con trỏ của Mat.
C# WPF thì sẽ dung Image hiển thị một WriteableBitmap. Cũng sẽ copy dữ lieu ảnh vào dữ lieu của WriteableBitmap.
C++ QT thì dung QLabel hiển thị một QPixmap. Khai báo một QImage để lưu dữ lieu ảnh. Sau đó chuyển QImage->QPixmap.
Cái khác mình không biết
E code bằng c++. Vì em build 1 thư viện xla cơ bản, từ đọc ghi, lưu trữ, các thuật toán tiền xử lý. Phần nhận dạng dùng svm. Nên e test trên console. K có giao diện. Dùng qt thì cũng như opencv, cũng dùng thêm tool bên ngoài , mà e lại chưa học qt, nên em dùng opencv hiển thị vậy, tiện so sánh kết quả của thư viện chạy với kết quả mình tự gõ.
Em muốn hiển thị khi chạy chương trình cho trực quan
Cách truy cập 1d trên
X là hàng. Y là cột phải k anh nhỉ