2011-12-02 25 views
14

पहला - मैं कुछ समय से इस पर काम कर रहा हूं और कई समाधानों की कोशिश की है, इसलिए मुझे Google पर मिलने वाला पहला लिंक न भेजें।एंड्रॉइड: कॉलबैक के साथ कैमरा पूर्वावलोकन कैसे प्रदर्शित करें?

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

सभी मामलों में मैं कैमरे का उपयोग कर रहा हूं .setPreviewCallbackWithBuffer(), जो कैमरा से अधिक तेज है .setPreviewCallback()। ऐसा लगता है कि अगर मैं पूर्वावलोकन प्रदर्शित नहीं कर रहा हूं, तो मुझे यहां 24 एफपीएस नहीं मिल सकते हैं। तो समस्या नहीं है। एक बिटमैप के रूप में एक SurfaceView पर

1. प्रदर्शन कैमरा पूर्वावलोकन:

मैं इन समाधानों की कोशिश की है। यह काम करता है, लेकिन प्रदर्शन लगभग 6fps है।

baos = new ByteOutputStream(); 
yuvimage=new YuvImage(cameraFrame, ImageFormat.NV21, prevX, prevY, null); 

yuvimage.compressToJpeg(new Rect(0, 0, prevX, prevY), 80, baos); 
jdata = baos.toByteArray(); 

bmp = BitmapFactory.decodeByteArray(jdata, 0, jdata.length); // Convert to Bitmap, this is the main issue, it takes a lot of time 

canvas.drawBitmap(bmp , 0, 0, paint); 
एक बनावट के रूप में एक GLSurfaceView पर


2. प्रदर्शन कैमरा पूर्वावलोकन। यहां मैं केवल ल्यूमिनेंस डेटा (ग्रेस्केल छवि) प्रदर्शित कर रहा था, जो काफी आसान है, इसे प्रत्येक फ्रेम पर केवल एक एरेकॉपी() की आवश्यकता होती है। मुझे लगभग 12 एफपीएस मिल सकते हैं, लेकिन मुझे पूर्वावलोकन में कुछ फ़िल्टर लागू करने की आवश्यकता है और ऐसा लगता है कि इसे ओपनजीएल ईएस 1 में तेजी से नहीं किया जा सकता है। इसलिए मैं इस समाधान का उपयोग नहीं कर सकता। another question में इसका कुछ विवरण।


3. एक (जीएल) SurfaceView YUV डेटा की प्रक्रिया करने के लिए NDK के प्रयोग पर प्रदर्शन कैमरा पूर्वावलोकन। मुझे एक समाधान here मिलता है जो कुछ सी फ़ंक्शन और एनडीके का उपयोग करता है। लेकिन मैंने इसे इस्तेमाल करने का प्रबंधन नहीं किया, here some more details। लेकिन वैसे भी, यह समाधान बाइटबफर को ओपनजीएल में एक बनावट के रूप में प्रदर्शित करने के लिए किया जाता है और यह पिछले प्रयास की तुलना में तेज़ नहीं होगा। तो मुझे int [] सरणी वापस करने के लिए इसे संशोधित करना होगा, जिसे canvas.drawBitmap() के साथ खींचा जा सकता है, लेकिन मुझे ऐसा करने के लिए पर्याप्त सी समझ में नहीं आता है।


तो क्या कोई अन्य तरीका है जिसे मैं याद कर रहा हूं या मैंने कोशिश किए गए प्रयासों में कुछ सुधार किया है?

किसी भी उत्तर के लिए धन्यवाद!

उत्तर

1

क्या यह आप नहीं चाहते हैं? बस एक SurfaceView अपने लेआउट में, तो कहीं न कहीं अपने init में onResume() की तरह उपयोग करें:

SurfaceView surfaceView = ... 
SurfaceHolder holder = surfaceView.getHolder(); 
... 
Camera camera = ...; 
camera.setPreviewDisplay(holder); 

यह बस के रूप में तेजी से आते ही उन्हें सीधे देखने के लिए फ्रेम भेजता है।

यदि आप ग्रेस्केल चाहते हैं, तो setColorEffect("mono") के साथ कैमरा पैरामीटर संशोधित करें।

+0

धन्यवाद, लेकिन मुझे वास्तव में कॉलबैक का उपयोग करने और छवियों को मैन्युअल रूप से प्रदर्शित करने की आवश्यकता है। मुझे केवल ग्रेस्केल छवि की आवश्यकता नहीं है, मैं कुछ और फिल्टर का उपयोग कर रहा हूं, मैंने अपने प्रश्न में उल्लेख नहीं किया है ... –

1

बहुत ही बुनियादी और सरल प्रभाव के लिए, वहाँ

Camera.Parameters parameters = mCamera.getParameters(); 
parameters.setColorEffect(Parameters.EFFECT_AQUA); 

मैं पता लगा है कि इस प्रभाव को अलग ढंग से डिवाइस के आधार पर करते हैं। उदाहरण के लिए, मेरे फोन (गैलेक्सी एस II) पर यह कॉमेस्टिक प्रभाव की तरह दिखता है क्योंकि आकाशगंगा एस 1 के विपरीत यह 'नीली छाया' है।

यह समर्थक है: यह लाइव-पूर्वावलोकन के रूप में काम कर रहा है।

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

+0

धन्यवाद, मुझे इन कैमरे के प्रभावों के बारे में पता है, लेकिन मैं कुछ विपरीत समायोजन, रंग प्रतिस्थापन करना चाहता था इत्यादि। लेकिन आप सही हैं, ऐसा लगता है कि वास्तव में लाइव पूर्वावलोकन के लिए एक अच्छा कामकाजी समाधान नहीं है, इसलिए मुझे कुछ ऐसा करना होगा जैसा आपने वर्णन किया है ...:/ –

7

मैं बिल्कुल एक ही मुद्दे पर काम कर रहा हूं, लेकिन आपके पास जितना दूर है उतना नहीं मिला है।

क्या आपने पिक्सल को सीधे जेपीईजी में एन्कोड किए बिना कैनवास पर चित्रित करने पर विचार किया है? ओपनसीवी किट http://sourceforge.net/projects/opencvlibrary/files/opencv-android/2.3.1/OpenCV-2.3.1-android-bin.tar.bz2/download (जो वास्तव में ओपनसीवी का उपयोग नहीं करता है; चिंता न करें), ट्यूटोरियल -0-एंड्रॉइड कैमरा नामक एक प्रोजेक्ट है जो वाईयूवी पिक्सेल को आरजीबी में परिवर्तित करने और फिर उन्हें सीधे बिटमैप में लिखने का प्रदर्शन करता है।

प्रासंगिक कोड अनिवार्य है:

public void onPreviewFrame(byte[] data, Camera camera, int width, int height) { 
    int frameSize = width*height; 
    int[] rgba = new int[frameSize+1]; 

    // Convert YUV to RGB 
    for (int i = 0; i < height; i++) 
     for (int j = 0; j < width; j++) { 
      int y = (0xff & ((int) data[i * width + j])); 
      int u = (0xff & ((int) data[frameSize + (i >> 1) * width + (j & ~1) + 0])); 
      int v = (0xff & ((int) data[frameSize + (i >> 1) * width + (j & ~1) + 1])); 
      y = y < 16 ? 16 : y; 

      int r = Math.round(1.164f * (y - 16) + 1.596f * (v - 128)); 
      int g = Math.round(1.164f * (y - 16) - 0.813f * (v - 128) - 0.391f * (u - 128)); 
      int b = Math.round(1.164f * (y - 16) + 2.018f * (u - 128)); 

      r = r < 0 ? 0 : (r > 255 ? 255 : r); 
      g = g < 0 ? 0 : (g > 255 ? 255 : g); 
      b = b < 0 ? 0 : (b > 255 ? 255 : b); 

      rgba[i * width + j] = 0xff000000 + (b << 16) + (g << 8) + r; 
     } 

    Bitmap bmp = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); 
    bmp.setPixels(rgba, 0/* offset */, width /* stride */, 0, 0, width, height); 
    Canvas canvas = mHolder.lockCanvas(); 
    if (canvas != null) { 
     canvas.drawBitmap(bmp, (canvas.getWidth() - width)/2, (canvas.getHeight() - height)/2, null); 
     mHolder.unlockCanvasAndPost(canvas); 
    } else { 
     Log.w(TAG, "Canvas is null!"); 
    } 
    bmp.recycle(); 
} 

बेशक आप इसे अनुकूलित करने के लिए अपनी जरूरतों को पूरा करना होगा (उदा। RGBA प्रत्येक फ्रेम का आवंटन नहीं), लेकिन यह एक शुरुआत हो सकती है। मुझे यह देखना अच्छा लगेगा कि यह आपके लिए काम करता है या नहीं - मैं अभी भी इस समय आपके लिए ऑर्थोगोनल समस्याएं लड़ रहा हूं।

+1

मैं कल इसे आजमाउंगा, लेकिन मैं काफी यकीन है कि कोई प्रदर्शन सुधार नहीं होगा, क्योंकि यह युवराज और बिटमैप फैक्ट्री कक्षाओं के संस्करण के समान ही कम काम करता है। लेकिन मैं इसे आज़मा दूंगा और हम देखेंगे। धन्यवाद। –

+1

तो, जैसा कि मैंने उम्मीद की थी, यह सभी मामलों से सबसे खराब प्रदर्शन है, भले ही मैंने इसे थोड़ा अनुकूलित करने की कोशिश की ... –

4

मुझे लगता है कि माइकल सही रास्ते पर है। सबसे पहले आप आरजीबी से ग्रेस्केल में कनवर्ट करने के लिए इस विधि को आजमा सकते हैं। स्पष्ट रूप से यह लगभग उतना ही काम कर रहा है जितना कि आप चाहते हैं, लेकिन जो कुछ आप चाहते हैं उसके लिए थोड़ा और संक्षेप में।

//YUV Space to Greyscale 
static public void YUVtoGrayScale(int[] rgb, byte[] yuv420sp, int width, int height){ 
    final int frameSize = width * height; 
    for (int pix = 0; pix < frameSize; pix++){ 
     int pixVal = (0xff & ((int) yuv420sp[pix])) - 16; 
     if (pixVal < 0) pixVal = 0; 
     if (pixVal > 255) pixVal = 255; 
     rgb[pix] = 0xff000000 | (pixVal << 16) | (pixVal << 8) | pixVal; 
    } 
} 

}

दूसरा, कचरा कलेक्टर के लिए काम का एक टन का निर्माण नहीं करतीं। आपके बिटमैप और सरणी एक निश्चित आकार होने जा रहे हैं। उन्हें एक बार बनाएं, फ़्रेम पूर्वावलोकन में नहीं।

कर कि आप कुछ है कि इस तरह दिखता है के साथ खत्म हो जाएगा:

public PreviewCallback callback = new PreviewCallback() { 
    @Override 
    public void onPreviewFrame(byte[] data, Camera camera) { 
     if ((mSelectView == null) || !inPreview) 
      return; 
     if (mSelectView.mBitmap == null) 
     { 
      //initialize SelectView bitmaps, arrays, etc 
      //mSelectView.mBitmap = Bitmap.createBitmap(mSelectView.mImageWidth, mSelectView.mImageHeight, Bitmap.Config.RGB_565); 
      //etc 

     } 
     //Pass Image Data to SelectView 
     System.arraycopy(data, 0, mSelectView.mYUVData, 0, data.length); 
     mSelectView.invalidate(); 
    } 
}; 

और फिर कैनवास जहां आप इसे इस तरह दिखता है रखना चाहते हैं:

class SelectView extends View { 
Bitmap mBitmap; 
Bitmap croppedView; 
byte[] mYUVData; 
int[] mRGBData; 
int mImageHeight; 
int mImageWidth; 

public SelectView(Context context){ 
    super(context); 
    mBitmap = null; 
    croppedView = null; 
} 

@Override 
protected void onDraw(Canvas canvas){ 
    if (mBitmap != null) 
    { 
     int canvasWidth = canvas.getWidth(); 
     int canvasHeight = canvas.getHeight(); 
     // Convert from YUV to Greyscale 
     YUVtoGrayScale(mRGBData, mYUVData, mImageWidth, mImageHeight); 
      mBitmap.setPixels(mRGBData, 0, mImageWidth, 0, 0, mImageWidth, mImageHeight); 
      Rect crop = new Rect(180, 220, 290, 400); 
     Rect dst = new Rect(0, 0, canvasWidth, (int)(canvasHeight/2)); 
     canvas.drawBitmap(mBitmap, crop, dst, null); 
    } 
    super.onDraw(canvas); 
} 

यह उदाहरण दिखाता है एक वास्तविक समय में कैमरा पूर्वावलोकन का फसल और विकृत चयन, लेकिन आपको विचार मिलता है। यह ग्रेस्केल में नेक्सस एस पर उच्च एफपीएस पर चलता है और आपकी आवश्यकताओं के लिए भी काम करना चाहिए।

+0

'दूसरा, कचरा कलेक्टर के लिए काम का एक टन न बनाएं।' आपका 'ऑन ड्रा' हमें अन्यथा बताता है। –

0

मुझे विश्वास है कि मैंने blog में पढ़ा है कि ग्रेस्केल डेटा पहले x * y बाइट्स में है। युव को ल्यूमिनेंस का प्रतिनिधित्व करना चाहिए, इसलिए डेटा वहां है, हालांकि यह एक सही ग्रेस्केल नहीं है। सापेक्ष चमक के लिए यह बहुत अच्छा है, लेकिन ग्रेस्केल नहीं है, क्योंकि प्रत्येक रंग आरजीबी में एक दूसरे के रूप में उज्ज्वल नहीं है। हरे रंग को आमतौर पर चमकदार रूपांतरणों में एक मजबूत वजन दिया जाता है। उम्मीद है की यह मदद करेगा!

0

क्या कोई विशेष कारण है कि आपको GLES 1.0 का उपयोग करने के लिए मजबूर किया गया है? Android SDK: Get raw preview camera image without displaying it

आम तौर पर यह GLES 2.0 के साथ संयोजन में Camera.setPreviewTexture() का उपयोग का उल्लेख है:

क्योंकि अगर नहीं, स्वीकार किए जाते हैं जवाब यहाँ देखें। जीएलएस 2.0 में आप स्क्रीन पर एक पूर्ण-स्क्रीन-क्वाड प्रस्तुत कर सकते हैं, और जो भी प्रभाव चाहते हैं उसे बना सकते हैं।

यह संभवतः सबसे तेज़ तरीका संभव है।

+1

उदाहरण: https://github.com/google/grafika/blob/master/src/com/android/grafika/CameraCaptureActivity.java। वर्तमान में इसमें एक शेडर है जो लाल रंग के चैनल में एक बी एंड डब्ल्यू छवि डालता है ("रोसीफ्रैगमेंट" के लिए खोजें)। आर/जी/बी के समान मूल्य को आवंटित करने से बी और डब्ल्यू छवि मिल जाएगी। – fadden

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