2012-11-28 38 views
9

Trong C++ dll của tôi, tôi đang tạo ra Mat từ mảng byte:OpenCV tạo Mat từ mảng byte

BYTE * ptrImageData; //Image data is in this array passed to this function 

Mat newImg = Mat(nImageHeight, nImageWidth, CV_8UC3, ptrImageData); 

Những hình ảnh được tạo ra với một số màu xám không phải là người gốc.

Đây có phải là cách thích hợp để tạo Mat từ mảng byte không?

Vui lòng xem mã

ptrImageData được chuyển đến tệp C++ từ mã C#.

mã C# để vượt qua các dữ liệu hình ảnh

System.Drawing.Image srcImage //Has the image 
MemoryStream ms = new MemoryStream(); 
Marshal.FreeHGlobal(ptrImageData); 
srcImage.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg); 
byte[] imgArray = ms.ToArray(); 
ms.Dispose(); 


int size1 = Marshal.SizeOf(imgArray[0]) * imgArray.Length; 
IntPtr ptrImageData = Marshal.AllocHGlobal(size1); 
Marshal.Copy(imgArray, 0, ptrImageData, imgArray.Length); 

//Calling C++ dll function 
ProcessImage(ptrImageData, srcImage.Width, srcImage.Height); 

Marshal.FreeHGlobal(ptrImageData); 
+1

Tôi nghĩ rằng mã C++ của bạn có một số sai lầm, Mat newImg (...), hoặc Mat * newImg = new Mat (..), ghi của bạn không phải là kiểu C++. – Healer

+0

@healer .. mã đúng. Trong đoạn mã trên, 'newImg' đang được khởi tạo bằng cách sử dụng hàm tạo' tường minh 'của lớp' Mat'. – sgarizvi

+0

Vui lòng cung cấp mã chi tiết hơn, như cách bạn hiển thị hình ảnh, bố cục của 'ptrImageData' là gì. – luhb

Trả lời

0

Vâng, đây là một cách để tạo ra một Mat từ một mảng byte. Bạn chỉ cần cẩn thận rằng mảng của bạn có chứa những gì bạn nghĩ nó.

Hình ảnh được tạo bằng một số màu xám không phải là màu gốc.

Vì vậy, bạn đang nhận được một hình ảnh trong newImg? Định dạng pixel của dữ liệu gốc là gì?

Có thể bạn đã chuyển đổi kênh màu đỏ và xanh dương. Dòng sau sẽ trao đổi các kênh:

cv::cvtColor(newImg,swappedImg,CV_RGB2BGR); 
0

Dưới đây là liên kết đến tài liệu: http://docs.opencv.org/modules/core/doc/basic_structures.html#mat-mat

Nói chung bạn nên chăm sóc về hai điều:

  1. Khi bạn truyền dữ liệu bên ngoài vào xây dựng ma trận , dữ liệu bên ngoài không tự động được phân bổ, vì vậy bạn nên cẩn thận. Nếu bạn muốn ma trận OpenCV quan tâm đến bộ nhớ, thì bạn nên sao chép ma trận (bạn có thể thực hiện theo nhiều cách, ví dụ như sử dụng phương thức Mat::clone hoặc Mat::copyTo.
  2. Dữ liệu ngoài có thể không liên tục, tức là kích thước của hàng có thể lớn hơn chiều rộng Nhân với số lượng kênh nhân với kích thước của phần tử dữ liệu Vì vậy, bạn có thể muốn chỉ định "bước" làm đối số cuối cùng của hàm tạo.Nếu bạn phân bổ dữ liệu ngoài theo cách thủ công và chắc chắn 100% là liên tục, thì bạn không thể vượt qua bước và dựa vào tự động tính toán bước.

tôi không quen với C#, nhưng có vẻ như với tôi rằng bạn phát hành dữ liệu ngay sau khi ProcessImage gọi. Vì vậy, nếu ProcessImage là không đồng bộ hoặc bằng cách nào đó lưu trữ ma trận của bạn (tức là tuổi thọ của ma trận là còn t hat ProcessImage gọi), sau đó bạn nên quan tâm về quản lý bộ nhớ.

1

Mã C++ xuất hiện ok, ở chỗ điều này tạo ra một gói ma trận cho dữ liệu hình ảnh được cung cấp, giả sử bộ đệm ở định dạng RGB8 thông thường. Lưu ý rằng hàm tạo này thực hiện không sao chép bộ đệm, do đó bộ đệm phải còn hiệu lực trong khoảng thời gian của phiên bản Mat này (hoặc được sao chép).

Mat newImg = Mat(nImageHeight, nImageWidth, CV_8UC3, ptrImageData); 

Có vẻ như sự cố nằm trong mã C# của bạn. Tôi không phải là nhà phát triển C#, nhưng tôi sẽ cố hết sức để giúp đỡ. Bạn đang tạo một luồng bộ nhớ và sử dụng codec JPEG để viết một phiên bản nén của hình ảnh vào bộ đệm như thể nó là một tập tin.Nhưng đó là không phải là định dạng dữ liệu mà cv::Mat đang chờ đợi, vì vậy, về cơ bản bạn sẽ thấy rác (dữ liệu nén được hiểu là không nén).

Với trường hợp System.Image.Drawing.Image, bạn có thể tạo đối tượng trực tiếp Bitmap trực tiếp (hoặc có thể sử dụng as, vì đây là thao tác đơn giản). Sau đó, bạn chỉ có thể sử dụng phương thức Bitmap.LockBits() tog lấy con trỏ đến dữ liệu hình ảnh cơ bản.

Bitmap bmp = new Bitmap(sourceImage); 

// Lock the bitmap's bits. 
Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height); 
System.Drawing.Imaging.BitmapData bmpData = 
    bmp.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, 
    bmp.PixelFormat); 

// Get the address of the first line. 
IntPtr ptr = bmpData.Scan0; 

// Declare an array to hold the bytes of the bitmap. 
int bytes = Math.Abs(bmpData.Stride) * bmp.Height; 
byte[] rgbBuffer = new byte[bytes]; 

// Copy the RGB values into the array. 
System.Runtime.InteropServices.Marshal.Copy(ptr, rgbBuffer, 0, bytes); 

// Do your OpenCV processing... 
// ... 

// Unlock the bits. 
bmp.UnlockBits(bmpData); 

và sau đó bạn có thể chuyển rgbBuffer sang OpenCV.

Tôi không tin rằng việc quản lý bộ nhớ trong mã ban đầu là hoàn toàn chính xác, nhưng dù sao ở trên sẽ làm việc cung cấp phạm vi quyền sở hữu bộ đệm nằm trong các cuộc gọi khóa và mở khóa. Nếu dữ liệu hình ảnh vượt quá khối mã này, bạn sẽ phải sao chép bộ đệm.

Hãy cẩn thận với định dạng pixel của bạn - bạn cần đảm bảo rằng phiên bản Image/Bitmap thực sự chứa dữ liệu RGB8. OpenCV's cv::Mat có nhiều cờ để bạn có thể làm việc với nhiều định dạng hình ảnh trong bộ nhớ khác nhau. Nhưng lưu ý rằng đây là không phải giống như định dạng trên đĩa (thường được nén), chẳng hạn như PNG, TIFF, v.v.

+0

Có thể đủ để thay đổi lệnh 'srcImage.Save (ms, System.Drawing.Imaging.ImageFormat.Jpeg)' để sử dụng 'ImageFormat.Bmp' thay vì chuyển đổi phức tạp được đề xuất ở đây – slawekwin

Các vấn đề liên quan