2011-06-25 18 views
32

वहाँ कई ट्यूटोरियल हैं जो बताते हैं कि एक साधारण कैमरा पूर्वावलोकन कैसे प्राप्त करें और एंड्रॉइड डिवाइस पर चलाना। लेकिन मुझे कोई उदाहरण नहीं मिला जो बताता है कि इसे प्रस्तुत करने से पहले छवि को कैसे छेड़छाड़ करना है।
मैं जो करना चाहता हूं वह अनुकरण करने के लिए कस्टम रंग फ़िल्टर लागू करना है। लाल और/या हरी कमी।मैं कैमरे के पूर्वावलोकन में कैसे छेड़छाड़ कर सकता हूं?

+1

यदि u कोड के साथ समझा सकता है, क्या उर करने का प्रयास कर, यह मदद करने के लिए आसान होगा आप – the100rabh

+0

https://github.com/whiskeysierra/impaired-vision/blob/master/src/org/whiskeysierra/impairedvision/ImpairedVision.java यह मेरे पास वर्तमान में है। मैं क्या करना चाहता हूं कि किसी प्रकार का कॉलबैक पंजीकृत कर रहा है (कैमरा। पूर्वावलोकनवॉलबैक?) जिसे मैं वर्तमान फ्रेम में हेरफेर करने के लिए उपयोग करता हूं। – whiskeysierra

+0

लिंक अब और काम नहीं करता है, लेकिन रेपो अभी भी मौजूद है, अगर कोई अभी भी दिलचस्पी लेता है: https://github.com/whiskeysierra/impaired-vision – whiskeysierra

उत्तर

49

मैंने इस पर कुछ शोध किया और एक काम (आईएसएच) उदाहरण को एक साथ रखा। मुझे जो मिला वह यहां है। कैमरे से कच्चे डेटा को बंद करना बहुत आसान है। यह एक यूयूवी बाइट सरणी के रूप में वापस आ गया है। इसे संशोधित करने में सक्षम होने के लिए आपको इसे सतह पर मैन्युअल रूप से आकर्षित करने की आवश्यकता होगी। ऐसा करने के लिए आपको एक SurfaceView होना होगा कि आप मैन्युअल रूप से ड्रा कॉल चला सकते हैं। कुछ झंडे आप सेट कर सकते हैं जो इसे पूरा करते हैं।

मैन्युअल रूप से ड्रॉ कॉल करने के लिए आपको बाइट सरणी को किसी प्रकार के बिटमैप में परिवर्तित करने की आवश्यकता होगी। बिटमैप्स और बिटमैप डिकोडर इस बिंदु पर वाईयूवी बाइट सरणी को बहुत अच्छी तरह से संभालने लगते नहीं हैं। इसके लिए एक बग दायर किया गया है लेकिन उस पर स्थिति क्या नहीं है, यह न करें। तो लोग बाइट सरणी को एक आरजीबी प्रारूप में खुद को डीकोड करने का प्रयास कर रहे हैं।

ऐसा लगता है कि डिकोडिंग मैन्युअल रूप से धीमा हो गया है और लोगों के पास सफलता के साथ विभिन्न डिग्री हैं। ऐसा कुछ वास्तव में एनडीके स्तर पर देशी कोड के साथ किया जाना चाहिए।

फिर भी, यह काम करना संभव है। इसके अलावा, मेरा छोटा डेमो सिर्फ मुझे कुछ घंटों में हैकिंग सामान खर्च कर रहा है (मुझे लगता है कि यह मेरी कल्पना को थोड़ा अधिक पकड़ा;))। तो कुछ tweaking के साथ संभावना है कि आप काम करने में कामयाब रहे हैं जो आप बेहतर में सुधार कर सकते हैं।

इस छोटे कोड स्निप में मुझे कुछ अन्य रत्न भी मिलते हैं। यदि आप चाहते हैं कि सतह पर आकर्षित करने में सक्षम होना है तो आप सतह के ऑन ड्रा फंक्शन को ओवरराइड कर सकते हैं - आप संभावित रूप से लौटाए गए कैमरे की छवि का विश्लेषण कर सकते हैं और ओवरले खींच सकते हैं - यह प्रत्येक फ्रेम को संसाधित करने की कोशिश करने से कहीं अधिक तेज़ होगा। इसके अलावा, अगर आप कैमरे के पूर्वावलोकन को दिखाना चाहते हैं तो इसकी आवश्यकता होगी, तो मैंने SurfaceHolder.SURFACE_TYPE_NORMAL को बदल दिया होगा। तो कोड में परिवर्तन की एक जोड़ी - बाहर टिप्पणी की कोड:

//try { mCamera.setPreviewDisplay(holder); } catch (IOException e) 
// { Log.e("Camera", "mCamera.setPreviewDisplay(holder);"); } 

और:

SurfaceHolder.SURFACE_TYPE_NORMAL //SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS - for preview to work 

आप वास्तविक पूर्वावलोकन के शीर्ष पर कैमरा पूर्वावलोकन के आधार पर फ्रेम ओवरले करने के लिए अनुमति चाहिए।

वैसे भी, यहां कोड का एक कामकाजी टुकड़ा है - आपको कुछ शुरू करने के लिए कुछ देना चाहिए।

बस इस तरह अपने दृश्यों में से एक में कोड की एक पंक्ति में कहें:

<pathtocustomview.MySurfaceView android:id="@+id/surface_camera" 
    android:layout_width="fill_parent" android:layout_height="10dip" 
    android:layout_weight="1"> 
</pathtocustomview.MySurfaceView> 

और कहीं अपने स्रोत में इस वर्ग में शामिल हैं:

package pathtocustomview; 

import java.io.IOException; 
import java.nio.Buffer; 

import android.content.Context; 
import android.graphics.Bitmap; 
import android.graphics.BitmapFactory; 
import android.graphics.Canvas; 
import android.graphics.Paint; 
import android.graphics.Rect; 
import android.hardware.Camera; 
import android.util.AttributeSet; 
import android.util.Log; 
import android.view.SurfaceHolder; 
import android.view.SurfaceHolder.Callback; 
import android.view.SurfaceView; 

public class MySurfaceView extends SurfaceView implements Callback, 
    Camera.PreviewCallback { 

    private SurfaceHolder mHolder; 

    private Camera mCamera; 
    private boolean isPreviewRunning = false; 
    private byte [] rgbbuffer = new byte[256 * 256]; 
    private int [] rgbints = new int[256 * 256]; 

    protected final Paint rectanglePaint = new Paint(); 

    public MySurfaceView(Context context, AttributeSet attrs) { 
    super(context, attrs); 
     rectanglePaint.setARGB(100, 200, 0, 0); 
     rectanglePaint.setStyle(Paint.Style.FILL); 
     rectanglePaint.setStrokeWidth(2); 

     mHolder = getHolder(); 
     mHolder.addCallback(this); 
     mHolder.setType(SurfaceHolder.SURFACE_TYPE_NORMAL); 
    } 

    @Override 
    protected void onDraw(Canvas canvas) { 
     canvas.drawRect(new Rect((int) Math.random() * 100, 
      (int) Math.random() * 100, 200, 200), rectanglePaint); 
     Log.w(this.getClass().getName(), "On Draw Called"); 
    } 

    public void surfaceChanged(SurfaceHolder holder, int format, int width, 
      int height) { 
    } 

    public void surfaceCreated(SurfaceHolder holder) { 
     synchronized (this) { 
      this.setWillNotDraw(false); // This allows us to make our own draw 
            // calls to this canvas 

      mCamera = Camera.open(); 

      Camera.Parameters p = mCamera.getParameters(); 
      p.setPreviewSize(240, 160); 
      mCamera.setParameters(p); 


      //try { mCamera.setPreviewDisplay(holder); } catch (IOException e) 
      // { Log.e("Camera", "mCamera.setPreviewDisplay(holder);"); } 

      mCamera.startPreview(); 
      mCamera.setPreviewCallback(this); 

     } 
    } 

    public void surfaceDestroyed(SurfaceHolder holder) { 
     synchronized (this) { 
      try { 
       if (mCamera != null) { 
        mCamera.stopPreview(); 
        isPreviewRunning = false; 
        mCamera.release(); 
       } 
      } catch (Exception e) { 
       Log.e("Camera", e.getMessage()); 
      } 
     } 
    } 

    public void onPreviewFrame(byte[] data, Camera camera) { 
     Log.d("Camera", "Got a camera frame"); 

     Canvas c = null; 

     if(mHolder == null){ 
      return; 
     } 

     try { 
      synchronized (mHolder) { 
       c = mHolder.lockCanvas(null); 

       // Do your drawing here 
       // So this data value you're getting back is formatted in YUV format and you can't do much 
       // with it until you convert it to rgb 
       int bwCounter=0; 
       int yuvsCounter=0; 
       for (int y=0;y<160;y++) { 
        System.arraycopy(data, yuvsCounter, rgbbuffer, bwCounter, 240); 
        yuvsCounter=yuvsCounter+240; 
        bwCounter=bwCounter+256; 
       } 

       for(int i = 0; i < rgbints.length; i++){ 
        rgbints[i] = (int)rgbbuffer[i]; 
       } 

       //decodeYUV(rgbbuffer, data, 100, 100); 
       c.drawBitmap(rgbints, 0, 256, 0, 0, 256, 256, false, new Paint()); 

       Log.d("SOMETHING", "Got Bitmap"); 

      } 
     } finally { 
      // do this in a finally so that if an exception is thrown 
      // during the above, we don't leave the Surface in an 
      // inconsistent state 
      if (c != null) { 
       mHolder.unlockCanvasAndPost(c); 
      } 
     } 
    } 
} 
+0

को आपकी विधि का प्रयास करने में केवल त्रुटियां मिलीं, क्या आपके पास शायद पूर्ण कार्य उदाहरण हो? धन्यवाद – goodm

+0

सी = mHolder.lockCanvas (शून्य); ग रिक्त है 08-05 18: 49: 23.419: ई/SurfaceHolder (13927): अपवाद ताला सतह 08-05 18: 49: 23.419: ई/SurfaceHolder (13927): java.lang.IllegalArgumentException 08- 05 18: 49: 23.419: ई/सरफेसहोल्डर (13 9 27): \t एंड्रॉइड.व्यू.सुरफेस.नेटिव लॉक कैनवास (मूल विधि) 08-05 18: 49: 23.419: ई/भूतलहोल्डर (13 9 27): \t एंड्रॉइड.व्यू पर। Surface.lockCanvas (Surface.java:243) 08-05 18: 49: 23.419: ई/SurfaceHolder (13927): android.view.SurfaceView $ 4.internalLockCanvas (SurfaceView.java:814) पर \t मदद कृपया –

+0

जहां क्या आप प्रीव्यूफ्रेम पर कॉल करते हैं? और "डेटा" क्या है? –

9

मैं walta के समाधान के लिए इस्तेमाल किया, लेकिन मैं था वाईयूवी रूपांतरण के साथ कुछ समस्याएं, कैमरा फ्रेम आउटपुट आकार और कैमरा रिलीज पर क्रैश।

अंत में निम्नलिखित कोड मेरे लिए काम किया:

public class MySurfaceView extends SurfaceView implements Callback, Camera.PreviewCallback { 

private static final String TAG = "MySurfaceView"; 

private int width; 
private int height; 

private SurfaceHolder mHolder; 

private Camera mCamera; 
private int[] rgbints; 

private boolean isPreviewRunning = false; 

private int mMultiplyColor; 

public MySurfaceView(Context context, AttributeSet attrs) { 
    super(context, attrs); 

    mHolder = getHolder(); 
    mHolder.addCallback(this); 
    mMultiplyColor = getResources().getColor(R.color.multiply_color); 
} 

// @Override 
// protected void onDraw(Canvas canvas) { 
// Log.w(this.getClass().getName(), "On Draw Called"); 
// } 

@Override 
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { 

} 

@Override 
public void surfaceCreated(SurfaceHolder holder) { 
    synchronized (this) { 
     if (isPreviewRunning) 
      return; 

     this.setWillNotDraw(false); // This allows us to make our own draw calls to this canvas 


     mCamera = Camera.open(); 
     isPreviewRunning = true; 
     Camera.Parameters p = mCamera.getParameters(); 
     Size size = p.getPreviewSize(); 
     width = size.width; 
     height = size.height; 
     p.setPreviewFormat(ImageFormat.NV21); 
     showSupportedCameraFormats(p); 
     mCamera.setParameters(p); 

     rgbints = new int[width * height]; 

     // try { mCamera.setPreviewDisplay(holder); } catch (IOException e) 
     // { Log.e("Camera", "mCamera.setPreviewDisplay(holder);"); } 

     mCamera.startPreview(); 
     mCamera.setPreviewCallback(this); 

    } 
} 


@Override 
public void surfaceDestroyed(SurfaceHolder holder) { 
    synchronized (this) { 
     try { 
      if (mCamera != null) { 
       //mHolder.removeCallback(this); 
       mCamera.setPreviewCallback(null); 
       mCamera.stopPreview(); 
       isPreviewRunning = false; 
       mCamera.release(); 
      } 
     } catch (Exception e) { 
      Log.e("Camera", e.getMessage()); 
     } 
    } 
} 

@Override 
public void onPreviewFrame(byte[] data, Camera camera) { 
    // Log.d("Camera", "Got a camera frame"); 
    if (!isPreviewRunning) 
     return; 

    Canvas canvas = null; 

    if (mHolder == null) { 
     return; 
    } 

    try { 
     synchronized (mHolder) { 
      canvas = mHolder.lockCanvas(null); 
      int canvasWidth = canvas.getWidth(); 
      int canvasHeight = canvas.getHeight(); 

      decodeYUV(rgbints, data, width, height); 

      // draw the decoded image, centered on canvas 
      canvas.drawBitmap(rgbints, 0, width, canvasWidth-((width+canvasWidth)>>1), canvasHeight-((height+canvasHeight)>>1), width, height, false, null); 

      // use some color filter 
      canvas.drawColor(mMultiplyColor, Mode.MULTIPLY); 

     } 
    } catch (Exception e){ 
     e.printStackTrace(); 
    } finally { 
     // do this in a finally so that if an exception is thrown 
     // during the above, we don't leave the Surface in an 
     // inconsistent state 
     if (canvas != null) { 
      mHolder.unlockCanvasAndPost(canvas); 
     } 
    } 
} 



/** 
* Decodes YUV frame to a buffer which can be use to create a bitmap. use 
* this for OS < FROYO which has a native YUV decoder decode Y, U, and V 
* values on the YUV 420 buffer described as YCbCr_422_SP by Android 
* 
* @param rgb 
*   the outgoing array of RGB bytes 
* @param fg 
*   the incoming frame bytes 
* @param width 
*   of source frame 
* @param height 
*   of source frame 
* @throws NullPointerException 
* @throws IllegalArgumentException 
*/ 
public void decodeYUV(int[] out, byte[] fg, int width, int height) throws NullPointerException, IllegalArgumentException { 
    int sz = width * height; 
    if (out == null) 
     throw new NullPointerException("buffer out is null"); 
    if (out.length < sz) 
     throw new IllegalArgumentException("buffer out size " + out.length + " < minimum " + sz); 
    if (fg == null) 
     throw new NullPointerException("buffer 'fg' is null"); 
    if (fg.length < sz) 
     throw new IllegalArgumentException("buffer fg size " + fg.length + " < minimum " + sz * 3/2); 
    int i, j; 
    int Y, Cr = 0, Cb = 0; 
    for (j = 0; j < height; j++) { 
     int pixPtr = j * width; 
     final int jDiv2 = j >> 1; 
    for (i = 0; i < width; i++) { 
     Y = fg[pixPtr]; 
     if (Y < 0) 
      Y += 255; 
     if ((i & 0x1) != 1) { 
      final int cOff = sz + jDiv2 * width + (i >> 1) * 2; 
      Cb = fg[cOff]; 
      if (Cb < 0) 
       Cb += 127; 
      else 
       Cb -= 128; 
      Cr = fg[cOff + 1]; 
      if (Cr < 0) 
       Cr += 127; 
      else 
       Cr -= 128; 
     } 
     int R = Y + Cr + (Cr >> 2) + (Cr >> 3) + (Cr >> 5); 
     if (R < 0) 
      R = 0; 
     else if (R > 255) 
      R = 255; 
     int G = Y - (Cb >> 2) + (Cb >> 4) + (Cb >> 5) - (Cr >> 1) + (Cr >> 3) + (Cr >> 4) + (Cr >> 5); 
     if (G < 0) 
      G = 0; 
     else if (G > 255) 
      G = 255; 
     int B = Y + Cb + (Cb >> 1) + (Cb >> 2) + (Cb >> 6); 
     if (B < 0) 
      B = 0; 
     else if (B > 255) 
      B = 255; 
     out[pixPtr++] = 0xff000000 + (B << 16) + (G << 8) + R; 
    } 
    } 

} 

private void showSupportedCameraFormats(Parameters p) { 
    List<Integer> supportedPictureFormats = p.getSupportedPreviewFormats(); 
    Log.d(TAG, "preview format:" + cameraFormatIntToString(p.getPreviewFormat())); 
    for (Integer x : supportedPictureFormats) { 
     Log.d(TAG, "suppoterd format: " + cameraFormatIntToString(x.intValue())); 
    } 

} 

private String cameraFormatIntToString(int format) { 
    switch (format) { 
    case PixelFormat.JPEG: 
     return "JPEG"; 
    case PixelFormat.YCbCr_420_SP: 
     return "NV21"; 
    case PixelFormat.YCbCr_422_I: 
     return "YUY2"; 
    case PixelFormat.YCbCr_422_SP: 
     return "NV16"; 
    case PixelFormat.RGB_565: 
     return "RGB_565"; 
    default: 
     return "Unknown:" + format; 

     } 
    } 
} 

इसका इस्तेमाल करने के लिए आपको गतिविधि के onCreate से निम्न कोड चलाएँ:

  SurfaceView surfaceView = new MySurfaceView(this, null); 
     RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT); 
     surfaceView.setLayoutParams(layoutParams); 
     mRelativeLayout.addView(surfaceView); 
+3

मैंने इस धागे और मेरे साथ प्रस्तुत विभिन्न समाधानों की भी कोशिश की। मुझे नीचे अपवाद मिलता है। मुझे नहीं लगता कि कोई एंड्रॉइड 4.4 ऑनवर्ड ई/सर्फेसहोल्डर (2872) से कम से कम प्रीव्यूफ्रेम विधि से कैनवास को लॉक कर सकता है: java.lang.IllegalArgumentException ई/सर्फेसहोल्डर (2872): \t android.view.Surface पर। देशी लॉक कैनवास (मूल विधि) ई/भूतलहोल्डर (2872): \t एंड्रॉइड.व्यू.सुरफेस.लॉक कैनवास (Surface.java343) –

+1

मैंने एक ही समाधान लागू किया लेकिन मेरे मामले में मुझे बिना किसी अपवाद के काले रंग की सतह मिल रही है। –

3

आप GPUImage को देखा है?

यह मूल रूप से ब्रैड लार्सन द्वारा बनाई गई ओएसएक्स/आईओएस लाइब्रेरी थी, जो ओपनजीएल/ईएस के आसपास एक उद्देश्य-सी रैपर के रूप में मौजूद है।

https://github.com/BradLarson/GPUImage

CyberAgent पर लोगों को एक Android बंदरगाह (जो पूर्ण सुविधा समता नहीं है) है, जो OpenGLES सामान की चोटी पर जावा रैपर का एक सेट है बना दिया है। यह अपेक्षाकृत उच्च स्तर है, और लागू करने के लिए बहुत आसान, जैसा कि ऊपर उल्लेख ही कार्यक्षमता का एक बहुत साथ है ...

https://github.com/CyberAgent/android-gpuimage

संबंधित मुद्दे

 संबंधित मुद्दे