2010-05-26 66 views
9

Tôi đang triển khai trình theo dõi mắt đơn giản, yêu cầu chụp nhanh nhanh những gì đang diễn ra trên màn hình cùng lúc bằng cách quay video từ webcam.Làm cách nào để chụp nhanh màn hình trong Java?

Vấn đề là cách thực hiện nó với Robot, được đề cập ở đây: https://stackoverflow.com/questions/2475303/java-library-for-capturing-active-window-screenshot cực kỳ chậm.

Nhân tiện, việc truy xuất video từ webcam hoạt động nhanh hơn nhiều và trả về mảng byte, quá trình xử lý rất nhanh.

Có ai biết giải pháp nhanh hơn không? Các thư viện C++, có thể được liên kết với Java để thực hiện điều này cũng có thể hữu ích.

Cảm ơn bạn!

UPDATE: Quyết định chuyển sang OpenCV, bây giờ tìm kiếm các cách để làm cho ảnh chụp màn hình với nó :)

+1

Câu trả lời cho câu hỏi được tham chiếu bao gồm hai cách hoàn toàn khác nhau khi sử dụng Robot. Bạn đã tạo hồ sơ nào? –

+0

Đã thêm nó vào bài đăng dưới đây – lyuba

+0

Kiểm tra [nircmd] (http://www.nirsoft.net/utils/nircmd.html). Nó đã có một func được xây dựng để làm điều này 'nircmd.exe cmdwait 0 savescreenshot" f : \ temp \ shot.png "' .Đặt chương trình này trong dự án của bạn và chạy nó bằng cách sử dụng ** Runtime() ** – meain

Trả lời

0

u chắc chắn sẽ cung cấp cho một shot để OpenCV

+0

Có cách nào để liên kết OpenCV với Java không? Tôi đã nghe nói về OpenCV, nhưng bây giờ tôi muốn thử Java cho nhiệm vụ này, và sẽ chuyển sang C++ chỉ khi nó thực sự cần thiết. – lyuba

+0

Đây là cách để làm điều đó: http://ubaa.net/shared/processing/opencv/ Tuy nhiên tôi đã quyết định thử C++, cảm ơn bạn đã truyền cảm hứng! – lyuba

+0

oh thanx cho java api, tôi đã thực sự tìm kiếm nó quá! –

0

Có thể bạn có thể tận dụng JMF .. Thanh toán các Screen Grabber code @ Oracle's site. Tôi nghĩ rằng nó sẽ giúp bạn giải quyết vấn đề của bạn.

+1

Từ mã nguồn, có vẻ như sử dụng Robot: http: // java. sun.com/javase/technologies/desktop/media/jmf/2.1.1/solutions/screengrabber/LiveStream.java Hoặc tôi có sai không? – lyuba

6

Cuộc gọi robot.createScreenCapture(captureSize); mất khoảng 20ms đối với tôi.

+0

Tôi nghĩ tốc độ sẽ phụ thuộc vào tốc độ khung hình/trình điều khiển của webcam được đề cập. –

+0

Tôi không có nhiều kinh nghiệm làm việc với dữ liệu từ webcam, nhưng tôi nghĩ họ sẽ cung cấp độ phân giải thấp hơn nhiều và luồng được nén trước. –

+0

Bạn nói đúng: Tôi có webcam Logitek C300 thông thường, vì vậy nó trả về 480 * 640 hình ảnh. Tôi sử dụng video cho Linux lib để xử lý video, nó được viết trên C và chạy hoàn toàn nhanh. Tôi cố gắng chụp ảnh màn hình với cùng tốc độ trong thời gian thực - nó ngay lập tức làm chậm quá trình. Tôi chụp ảnh đó như Ảnh chụp màn hình BufferedImage = robot.createScreenCapture (Hình chữ nhật mới (Toolkit.getDefaultToolkit(). GetScreenSize())); Có thể xảy ra do BurrefedImage không? Có cách nào để các mảng bit từ Robot? – lyuba

11

Dưới đây là một phiên bản đặc trưng cho Windows sử dụng JNA mà tôi đang sử dụng thuộc một trong các dự án của tôi.

Tôi nhận thấy nó là một đơn đặt hàng có cường độ nhanh hơn Robot, ngay cả với chi phí cuộc gọi gốc.

import java.awt.Rectangle; 
import java.awt.image.BufferedImage; 
import java.awt.image.ColorModel; 
import java.awt.image.DataBuffer; 
import java.awt.image.DataBufferInt; 
import java.awt.image.DataBufferUShort; 
import java.awt.image.DirectColorModel; 
import java.awt.image.Raster; 
import java.awt.image.WritableRaster; 

import com.sun.jna.Native; 
import com.sun.jna.platform.win32.W32API; 
import com.sun.jna.win32.W32APIOptions; 

public class JNAScreenShot { 

    public static BufferedImage getScreenshot(Rectangle bounds) { 
     W32API.HDC windowDC = GDI.GetDC(USER.GetDesktopWindow()); 
     W32API.HBITMAP outputBitmap = 
      GDI.CreateCompatibleBitmap(windowDC, 
             bounds.width, bounds.height); 
     try { 
      W32API.HDC blitDC = GDI.CreateCompatibleDC(windowDC); 
      try { 
       W32API.HANDLE oldBitmap = 
        GDI.SelectObject(blitDC, outputBitmap); 
       try { 
        GDI.BitBlt(blitDC, 
           0, 0, bounds.width, bounds.height, 
           windowDC, 
           bounds.x, bounds.y, 
           GDI32.SRCCOPY); 
       } finally { 
        GDI.SelectObject(blitDC, oldBitmap); 
       } 
       GDI32.BITMAPINFO bi = new GDI32.BITMAPINFO(40); 
       bi.bmiHeader.biSize = 40; 
       boolean ok = 
        GDI.GetDIBits(blitDC, outputBitmap, 0, bounds.height, 
            (byte[]) null, bi, GDI32.DIB_RGB_COLORS); 
       if (ok) { 
        GDI32.BITMAPINFOHEADER bih = bi.bmiHeader; 
        bih.biHeight = - Math.abs(bih.biHeight); 
        bi.bmiHeader.biCompression = 0; 
        return bufferedImageFromBitmap(blitDC, outputBitmap, bi); 
       } else { 
        return null; 
       } 
      } finally { 
       GDI.DeleteObject(blitDC); 
      } 
     } finally { 
      GDI.DeleteObject(outputBitmap); 
     } 
    } 

    private static BufferedImage 
    bufferedImageFromBitmap(GDI32.HDC  blitDC, 
          GDI32.HBITMAP outputBitmap, 
          GDI32.BITMAPINFO bi) { 
     GDI32.BITMAPINFOHEADER bih = bi.bmiHeader; 
     int height = Math.abs(bih.biHeight); 
     final ColorModel cm; 
     final DataBuffer buffer; 
     final WritableRaster raster; 
     int strideBits = 
      (bih.biWidth * bih.biBitCount); 
     int strideBytesAligned = 
      (((strideBits - 1) | 0x1F) + 1) >> 3; 
     final int strideElementsAligned; 
     switch (bih.biBitCount) { 
     case 16: 
      strideElementsAligned = strideBytesAligned/2; 
      cm = new DirectColorModel(16, 0x7C00, 0x3E0, 0x1F); 
      buffer = 
       new DataBufferUShort(strideElementsAligned * height); 
      raster = 
       Raster.createPackedRaster(buffer, 
              bih.biWidth, height, 
              strideElementsAligned, 
              ((DirectColorModel) cm).getMasks(), 
              null); 
      break; 
     case 32: 
      strideElementsAligned = strideBytesAligned/4; 
      cm = new DirectColorModel(32, 0xFF0000, 0xFF00, 0xFF); 
      buffer = 
       new DataBufferInt(strideElementsAligned * height); 
      raster = 
       Raster.createPackedRaster(buffer, 
              bih.biWidth, height, 
              strideElementsAligned, 
              ((DirectColorModel) cm).getMasks(), 
              null); 
      break; 
     default: 
      throw new IllegalArgumentException("Unsupported bit count: " + bih.biBitCount); 
     } 
     final boolean ok; 
     switch (buffer.getDataType()) { 
      case DataBuffer.TYPE_INT: 
       { 
        int[] pixels = ((DataBufferInt) buffer).getData(); 
        ok = GDI.GetDIBits(blitDC, outputBitmap, 0, raster.getHeight(), pixels, bi, 0); 
       } 
       break; 
      case DataBuffer.TYPE_USHORT: 
       { 
        short[] pixels = ((DataBufferUShort) buffer).getData(); 
        ok = GDI.GetDIBits(blitDC, outputBitmap, 0, raster.getHeight(), pixels, bi, 0); 
       } 
       break; 
      default: 
       throw new AssertionError("Unexpected buffer element type: " + buffer.getDataType()); 
     } 
     if (ok) { 
      return new BufferedImage(cm, raster, false, null); 
     } else { 
      return null; 
     } 
    } 

    private static final User32 USER = User32.INSTANCE; 

    private static final GDI32 GDI = GDI32.INSTANCE; 

} 

interface GDI32 extends com.sun.jna.platform.win32.GDI32 { 
    GDI32 INSTANCE = 
     (GDI32) Native.loadLibrary(GDI32.class); 
    boolean BitBlt(HDC hdcDest, 
        int nXDest, 
        int nYDest, 
        int nWidth, 
        int nHeight, 
        HDC hdcSrc, 
        int nXSrc, 
        int nYSrc, 
        int dwRop); 
    HDC GetDC(HWND hWnd); 
    boolean GetDIBits(HDC dc, HBITMAP bmp, int startScan, int scanLines, 
         byte[] pixels, BITMAPINFO bi, int usage); 
    boolean GetDIBits(HDC dc, HBITMAP bmp, int startScan, int scanLines, 
         short[] pixels, BITMAPINFO bi, int usage); 
    boolean GetDIBits(HDC dc, HBITMAP bmp, int startScan, int scanLines, 
         int[] pixels, BITMAPINFO bi, int usage); 
    int SRCCOPY = 0xCC0020; 
} 

interface User32 extends com.sun.jna.platform.win32.User32 { 
    User32 INSTANCE = 
     (User32) Native.loadLibrary(User32.class, 
            W32APIOptions.UNICODE_OPTIONS); 
    HWND GetDesktopWindow(); 
} 
+2

Phiên bản nào của JNA thực hiện việc này? Tôi không thể làm cho nó biên dịch trong bất kỳ phiên bản nào tôi đã tìm thấy. Phiên bản 3.3.0 mới nhất đã chia nhỏ com.sun.jna.platform.win32.W32API thành nhiều phần và các phiên bản cũ hơn không thể tìm thấy com.sun.jna.platform.win32. Tôi đã thử 3.2.3, 3.2.5, 3.2.7 và 3.3.0. – George

+0

hey có cách nào để lưu nội dung của HDC không? Tôi hiểu làm thế nào để lưu chúng như jpegs, nhưng tôi đã tự hỏi nếu có một cách thực sự nhanh chóng để lưu các nội dung của một HDC vì vậy tôi sau đó có thể resue chúng để tạo ra jpegs – user4090

+1

không thể làm cho nó hoạt động. Bạn đã sử dụng phiên bản JNA nào @finnw? – Horen

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