問題描述
我想使用 glReadPixels() 從動畫中獲取每個 OpenGL 幀,并將數據轉換為 OpenCV::Mat.我知道 glReadPixels() 從下到上,從左到右按行獲取數據.另一方面,OpenCV 以不同的方式存儲數據.
I want to get every OpenGL frame from an animation with glReadPixels() and convert the data to OpenCV::Mat. I know that glReadPixels() gets the data by rows from the lower one to upper one, from left to right. On the other hand, OpenCV stores the data differently.
有沒有人知道任何可以幫助我將數據從 glReadPixels 轉換為 C++ 中的 OpenCV:Mat 的庫或任何教程/示例?
Does anybody know any library or any tutorial/example that helps me to convert data from glReadPixels to a OpenCV:Mat in C++?
總結
OpenGL frame -----------------------> CV::Mat
Data from left to right, Data from left to right,
bottom to top. top to bottom.
推薦答案
首先我們創建一個空的(或單元化的)cv::Mat
以便我們的數據可以直接讀入.這可以在啟動時完成一次,但另一方面 cv::Mat::create
當圖像已經具有匹配的大小和類型時并不會真正花費太多.類型取決于您的需求,通常類似于 CV_8UC3
用于 24 位彩色圖像.
First we create an empty (or unititialized) cv::Mat
for our data to be read into directly. This can be done once at startup, but on the other hand cv::Mat::create
doesn't really cost much when the image already has matching size and type. The type depends on your needs, usually it's something like CV_8UC3
for a 24-bit color image.
cv::Mat img(height, width, CV_8UC3);
或
img.create(height, width, CV_8UC3);
然后您必須考慮 cv::Mat
不必連續存儲圖像行.每行末尾可能有一個小的填充值,以使行 4 字節對齊(或 8 字節?).所以你需要弄亂像素存儲模式:
Then you have to account for cv::Mat
not neccessarily storing image rows contiguously. There might be a small padding value at the end of each row to make rows 4-byte aligned (or 8?). So you need to mess with the pixel storage modes:
//use fast 4-byte alignment (default anyway) if possible
glPixelStorei(GL_PACK_ALIGNMENT, (img.step & 3) ? 1 : 4);
//set length of one complete row in destination data (doesn't need to equal img.cols)
glPixelStorei(GL_PACK_ROW_LENGTH, img.step/img.elemSize());
接下來,矩陣的類型會影響glReadPixels
的格式和類型參數.如果你想要彩色圖像,你必須記住 OpenCV 通常以 BGR 順序存儲顏色值,所以你需要使用 GL_BGR(A)
(這是在 OpenGL 1.2 中添加的)而不是 GL_RGB(A)
.對于一個分量圖像,使用 GL_LUMINANCE
(對各個顏色分量求和)或 GL_RED
、GL_GREEN
、...(獲取單個分量).因此,對于我們的 CV_8UC3
圖像,將其直接讀入 cv::Mat
的最終調用將是:
Next, the type of the matrix influences the format and type parameters of glReadPixels
. If you want color images you have to keep in mind that OpenCV usually stores color values in BGR order, so you need to use GL_BGR(A)
(which were added with OpenGL 1.2) instead of GL_RGB(A)
. For one component images use either GL_LUMINANCE
(which sums the individual color components) or GL_RED
, GL_GREEN
, ... (to get an individual component). So for our CV_8UC3
image the final call to read it directly into the cv::Mat
would be:
glReadPixels(0, 0, img.cols, img.rows, GL_BGR, GL_UNSIGNED_BYTE, img.data);
最后,OpenCV 從上到下存儲圖像.因此,您可能需要在獲取它們后翻轉它們,或者首先在 OpenGL 中渲染它們(這可以通過調整投影矩陣來完成,但在這種情況下要注意三角形方向).要垂直翻轉 cv::Mat
,您可以使用 cv::flip
:
Finally, OpenCV stores images from top to bottom. So you may need to either flip them after getting them or render them flipped in OpenGL in the first place (this can be done by adjusting the projection matrix, but keep an eye on triangle orientation in this case). To flip a cv::Mat
vertically, you can use cv::flip
:
cv::flip(img, flipped, 0);
所以要記住 OpenCV:
So to keep in mind OpenCV:
- 從上到下,從左到右存儲圖像
- 按 BGR 順序存儲彩色圖像
- 可能不會將圖像行存儲得緊湊
這篇關于將數據從 glReadPixels() 轉換為 OpenCV::Mat的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網!