之前寫Java人臉識別爬蟲的時候遇到的問題,最先的時候是用tempfile的形式去解決識別的問題,每個爬蟲線程爬取圖片到本地,保存爲tempfile,而後opencv再讀取出來作處理和識別,可是這樣涉及磁盤io,爬蟲性能異常緩慢,因此後面思考了一段時間琢磨出來再內存裏面對圖像進行轉化,本質上,圖像數據對Java來講都是bytes[]串,因此個人轉化過程的思路,就是把byte串取出來,從新組裝。
opencv Mat轉BufferImagejava
public static BufferedImage toBufferedImage(Mat matrix) { int type = BufferedImage.TYPE_BYTE_GRAY; if (matrix.channels() > 1) { type = BufferedImage.TYPE_3BYTE_BGR; } int bufferSize = matrix.channels() * matrix.cols() * matrix.rows(); byte[] buffer = new byte[bufferSize]; matrix.get(0, 0, buffer); // get all pixel from martix BufferedImage image = new BufferedImage(matrix.cols(), matrix.rows(), type); final byte[] targetPixels = ((DataBufferByte) image.getRaster().getDataBuffer()).getData(); System.arraycopy(buffer, 0, targetPixels, 0, buffer.length); return image; }
BufferImage轉爲opencv Mat數組
public static Mat bufferToMartix(BufferedImage image) { Mat mat = new Mat(image.getHeight(), image.getWidth(), CvType.CV_8UC3); byte[] data = ((DataBufferByte) image.getRaster().getDataBuffer()).getData(); if (mat != null) { try { mat.put(0, 0, data); } catch (Exception e) { return null; } } return mat; }
byte數組轉opencv Mat函數
public static Mat bufferToMartix(byte[] image) throws IOException { BufferedImage bImage = ImageIO.read(new ByteArrayInputStream(image)); byte[] bytes = ((DataBufferByte) bImage.getRaster().getDataBuffer()).getData(); Mat data = new Mat(bImage.getHeight(), bImage.getWidth(), CvType.CV_8UC3); data.put(0, 0, bytes); return data; }
有意思的是,當我讓一個BufferedImage嵌套爲性能
//這裏假設b_image裏面包含有圖像數據 BufferedImage b_image=b_image=new BufferedImage(); Mat matrix=toBufferedImage(bufferToMartix(b_image))
的時候,JVM機率死掉報出Core Error,因而我分離了這兩個函數避免嵌套使用,沒有去深究這個問題,猜想這可能與JVM的GC(垃圾回收)有關係,並且就算不出現JVM致命錯誤,這樣出來的圖像也是有問題的,會缺失不少數據,而後變成一堆噪聲和一片白,直觀感受就是toBufferedImage調用結束後圖像數據內存就被釋放掉了,當bufferToMartix從後面執行的時候取了一樣大小的內存區塊當作圖像,隨機產生了JVM致命內存衝突,或者不衝突可是數據混亂的問題,由於不是專業Java這個地方還待研究。線程