2010-05-26 10 views
9

Estoy implementando un rastreador de ojos simple, que requiere captura de pantalla rápida de lo que está sucediendo en la pantalla simultáneamente con la captura del video de la cámara web.Cómo tomar capturas de pantalla rápidamente en Java?

La cosa es que la manera de hacerlo con Robot, mencionado aquí: https://stackoverflow.com/questions/2475303/java-library-for-capturing-active-window-screenshot es extremadamente lento.

Por cierto, la recuperación del video de una cámara web funciona mucho más rápido y devuelve la matriz de bytes, que es muy rápida de procesar.

¿Alguien conoce una solución más rápida? Las bibliotecas C++, que pueden vincularse a Java para hacer esto, también pueden ser útiles.

Gracias!

ACTUALIZACIÓN: decidió cambiar a OpenCV, ahora está buscando la manera de hacer captura de pantalla con él :)

+1

Las respuestas a la pregunta de referencia incluyen dos formas completamente diferentes de usar Robot. ¿Cuál perfil? –

+0

Se agregó a la publicación a continuación – lyuba

+0

Consulte [nircmd] (http://www.nirsoft.net/utils/nircmd.html). Tiene una función incorporada para hacer esto 'nircmd.exe cmdwait 0 savescreenshot" f : \ temp \ shot.png "'. Coloque este programa en su proyecto y ejecútelo con ** Runtime() ** – meain

Respuesta

0

u debe definitivamente dar un tiro a OpenCV

+0

¿Hay alguna forma de vincular OpenCV a Java? He oído hablar de OpenCV, pero ahora quiero probar Java para esta tarea, y cambiaré a C++ solo si realmente lo necesito. – lyuba

+0

Aquí está la manera de hacerlo: http://ubaa.net/shared/processing/opencv/ Sin embargo, decidí probar C++, ¡gracias por la inspiración! – lyuba

+0

oh gracias por la api de Java, ¡en realidad yo también lo estaba buscando! –

0

puede ser usted puede hacer uso de JMF .. Pedido del Screen Grabber code @ Oracle's site. Creo que te ayudará a resolver tu problema.

+1

Al igual que el código fuente, parece que también usa el Robot: http: // java. sun.com/javase/technologies/desktop/media/jmf/2.1.1/solutions/screengrabber/LiveStream.java ¿O estoy equivocado? – lyuba

6

La llamada robot.createScreenCapture(captureSize); tarda aproximadamente 20ms para mí.

+0

Creo que la velocidad dependerá de la velocidad de cuadro/controladores de la cámara web en cuestión. –

+0

No tengo mucha experiencia trabajando con datos de cámaras web, pero pensé que proporcionarían una resolución mucho menor y flujos precomprimidos. –

+0

Tiene razón: tengo la cámara web Logitek C300 normal, por lo que devuelve 480 * 640 imágenes. Uso Video para Linux lib para procesar video, está escrito en C y funciona perfectamente rápido. Intenté capturar la captura de pantalla con la misma velocidad en tiempo real, ralentiza inmediatamente el proceso. Capturo como Captura de pantalla BufferedImage = robot.createScreenCapture (new Rectangle (Toolkit.getDefaultToolkit(). GetScreenSize())); ¿Puede suceder debido a la imagen de Burrefed? ¿Hay alguna forma de la matriz de bits de Robot? – lyuba

11

Aquí hay una versión específica de Windows usando JNA que estoy usando en uno de mis proyectos.

He encontrado que es una orden de magnitud más rápida que Robot, incluso con la sobrecarga de llamada nativa.

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

¿Qué versión de JNA usa esto? No puedo hacer que compile en ninguna de las versiones que he encontrado. La última versión 3.3.0 ha dividido com.sun.jna.platform.win32.W32API en partes, y las versiones anteriores no pueden encontrar com.sun.jna.platform.win32. He intentado 3.2.3, 3.2.5, 3.2.7 y 3.3.0. – George

+0

hey ¿hay alguna manera de guardar el contenido de un HDC? Entiendo cómo guardarlos como jpegs, pero me preguntaba si había otra manera realmente rápida de guardar los contenidos de un HDC para que luego pueda recuperarlos y crear jpegs. – user4090

+1

tampoco lo pudo hacer funcionar. ¿Qué versión de JNA usaste @finnw? – Horen

Cuestiones relacionadas