2013-02-19 13 views
21

Jak przekonwertować obraz BufferedImage na matę w OpenCV? Im przy użyciu opakowania java dla OpenCV (nie JavaCV). Ponieważ jestem nowy w OpenCV mam pewne problemy ze zrozumieniem, jak działa Mata.Konwersja obrazu BufferedImage na Matę w opencv

Chcę zrobić coś takiego. (Na podstawie odpowiedzi Teda W.):

  BufferedImage image = ImageIO.read(b.getClass().getResource("Lena.png")); 

      int rows = image.getWidth(); 
      int cols = image.getHeight(); 
      int type = CvType.CV_16UC1; 
      Mat newMat = new Mat(rows,cols,type); 

      for(int r=0; r<rows; r++){ 
       for(int c=0; c<cols; c++){ 
        newMat.put(r, c, image.getRGB(r, c)); 
       } 
      } 

      Highgui.imwrite("Lena_copy.png",newMat); 

To nie działa. "Lena_copy.png" to tylko czarny obraz z prawidłowymi wymiarami.

+0

jest to niestandardowe java wrapper? dla 'javacv' jest to po prostu' IplImage.createFrom (bufferedImage) '. proszę zaksięgować kod, w którym utknąłeś? –

+2

Opencv ma własne powiązanie Java od wersji 2.4.4. http://opencv.org/opencv-java-api.html – Jompa234

+0

Widzę, nie sprawdziłem jeszcze, dzięki –

Odpowiedz

23

ja też starałem się zrobić to samo , ze względu na konieczność łączenia obrazów przetworzonych z dwiema bibliotekami. I próbowałem zrobić to wstawić byte[] do Mat zamiast wartości RGB. I zadziałało! Więc co zrobiłem było:

1.Converted BufferedImage do tablicy bajtów z:

byte[] pixels = ((DataBufferByte) image.getRaster().getDataBuffer()).getData(); 

2. Następnie można po prostu umieścić go Mat jeśli typ ustawiony CV_8UC3

image_final.put(0, 0, pixels); 

Edytuj: Możesz również spróbować wykonać odwrotność, jak na this answer

+4

Cóż, jest coś, co viktorich nie powiedział w swojej odpowiedzi. Obiekt BufferedImage musi być zadeklarowany w następujący sposób: 'img = new BufferedImage (320, 240, BufferedImage.TYPE_3BYTE_BGR);'
'img.setRGB (0, 0, 320, 240, intArray, 0, 320);' In other sposób, powyższy kod nie zadziała. –

+0

Kod zadziała również w innych przypadkach. Oba formaty muszą się zgadzać, na przykład 'BufferedImage.TYPE_BYTE_GRAY' i' CV_8UC (1) 'działają również. – Mene

+0

W jakiej wersji działa ta biblioteka? To nie działa dla mnie (klasa Mat nie ma tej metody umieszczonej z taką sygnaturą), używam bytedeco javacv 1.3.2. –

1

Jeden prosty sposób byłoby utworzyć nowy użyciu

Mat newMat = Mat(rows, cols, type); 

następnie uzyskać wartości pikseli z Twojego BufferedImage i wprowadzane do NEWMAT użyciu

newMat.put(row, col, pixel); 
2

Znalazłem rozwiązanie here. Rozwiązanie jest podobne do Andriys.

Camera c; 
c.Connect(); 
c.StartCapture(); 
Image f2Img, cf2Img; 
c.RetrieveBuffer(&f2Img); 
f2Img.Convert(FlyCapture2::PIXEL_FORMAT_BGR, &cf2Img); 
unsigned int rowBytes = (double)cf2Img.GetReceivedDataSize()/(double)cf2Img.GetRows(); 

cv::Mat opencvImg = cv::Mat(cf2Img.GetRows(), cf2Img.GetCols(), CV_8UC3, cf2Img.GetData(),rowBytes); 
+0

Wymagałoby to JNI. –

-6

Można to zrobić w OpenCV następująco:

File f4 = new File("aa.png"); 
Mat mat = Highgui.imread(f4.getAbsolutePath()); 
12

Ten pracował dobrze dla mnie, a to trwa od 0 do 1 ms do wykonania.

public static Mat bufferedImageToMat(BufferedImage bi) { 
    Mat mat = new Mat(bi.getHeight(), bi.getWidth(), CvType.CV_8UC3); 
    byte[] data = ((DataBufferByte) bi.getRaster().getDataBuffer()).getData(); 
    mat.put(0, 0, data); 
    return mat; 
} 
+0

Dziękuję. Powyższa funkcjonalność sprawdziła się przy niewielkiej zmianie. Mam do czynienia z obrazami jednokanałowymi w skali szarości. Użyłem 'Mat mat = new Mat (bi.getHeight(), bi.getWidth(), CvType.CV_8UC1);' i to działało dla mnie. –

+0

Jak zrobisz zdjęcia RGBA? – arqam

1

Używam następującego kodu w moim programie.

protected Mat img2Mat(BufferedImage in) { 
     Mat out; 
     byte[] data; 
     int r, g, b; 

     if (in.getType() == BufferedImage.TYPE_INT_RGB) { 
      out = new Mat(in.getHeight(), in.getWidth(), CvType.CV_8UC3); 
      data = new byte[in.getWidth() * in.getHeight() * (int) out.elemSize()]; 
      int[] dataBuff = in.getRGB(0, 0, in.getWidth(), in.getHeight(), null, 0, in.getWidth()); 
      for (int i = 0; i < dataBuff.length; i++) { 
       data[i * 3] = (byte) ((dataBuff[i] >> 0) & 0xFF); 
       data[i * 3 + 1] = (byte) ((dataBuff[i] >> 8) & 0xFF); 
       data[i * 3 + 2] = (byte) ((dataBuff[i] >> 16) & 0xFF); 
      } 
     } else { 
      out = new Mat(in.getHeight(), in.getWidth(), CvType.CV_8UC1); 
      data = new byte[in.getWidth() * in.getHeight() * (int) out.elemSize()]; 
      int[] dataBuff = in.getRGB(0, 0, in.getWidth(), in.getHeight(), null, 0, in.getWidth()); 
      for (int i = 0; i < dataBuff.length; i++) { 
       r = (byte) ((dataBuff[i] >> 0) & 0xFF); 
       g = (byte) ((dataBuff[i] >> 8) & 0xFF); 
       b = (byte) ((dataBuff[i] >> 16) & 0xFF); 
       data[i] = (byte) ((0.21 * r) + (0.71 * g) + (0.07 * b)); 
      } 
     } 
     out.put(0, 0, data); 
     return out; 
    } 

referencyjny: here

5

Nie chcemy mieć do czynienia z wielkim tablicy pikseli? Wystarczy skorzystać z tej

BufferedImage do Mat

public static Mat BufferedImage2Mat(BufferedImage image) throws IOException { 
    ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); 
    ImageIO.write(image, "jpg", byteArrayOutputStream); 
    byteArrayOutputStream.flush(); 
    return Imgcodecs.imdecode(new MatOfByte(byteArrayOutputStream.toByteArray()), Imgcodecs.CV_LOAD_IMAGE_UNCHANGED); 
} 

Mata do BufferedImage

public static BufferedImage Mat2BufferedImage(Mat matrix)throws IOException { 
    MatOfByte mob=new MatOfByte(); 
    Imgcodecs.imencode(".jpg", matrix, mob); 
    return ImageIO.read(new ByteArrayInputStream(mob.toArray())); 
} 
+0

Fajnie, dziękuję. To rozwiązanie działa niezależnie od formatu obrazu wejściowego BufferedImage. Działa dla 24-bitowego JPG i jednocześnie dla 32-bitowego formatu PNG. – asmaier