Ruota l'anteprima della telecamera in Ritratto Android OpenCV Camera

Sto provando ad usare OpenCV 2.4.3.2 per creare un'applicazione per la camera e fare qualche elaborazione opencv. Vorrei che fosse in grado di avere più orientamenti dell'interface utente, non solo Landscape.

Il problema è che quando cambio l'orientamento in ritratto, l'image esce lateralmente.

  • ListFragment onPrepareOptionsMenu chiamato prima di onCreate. Perché e come risolvere / bypassare?
  • Devo utilizzare diversi ID unità di annunci AdMob in diverse attività?
  • Estendi stringhe per il progetto Android
  • EditText all'interno di ListView non resterà concentrato
  • Il modo migliore per unire le tabelle utilizzando sqlite in android
  • Dialogo personalizzato con setMultiChoiceItems
  • Capisco che potrei solo ruotare l'image di input prima di fare l'elaborazione delle immagini (e quindi lasciare l'orientamento come solo paesaggio), che funziona bene e non funziona, ma non risolve il problema che il resto del mio UI sarà nell'orientamento sbagliato .

    Ho anche provato a utilizzare questo codice per ruotare la camera 90deg, ma semplicemente non sembra funzionare.

    mCamera.setDisplayOrientation(90); 

    Esso non ha alcun effetto, o talvolta solo l'anteprima viene eliminata

    Qualcuno ha fatto questo con successo con OpenCV? La mia class si estende da JavaCameraView. immagine ritratto con anteprima laterale

    Modifica

    Ho fatto un miglioramento, vale a dire che ho ruotato l'image all'interno di OpenCV come è visualizzata nella class CameraBridgeViewBase.java.

    Nel metodo di erogazione e disegna struttura:

     if (canvas != null) { canvas.drawColor(0, android.graphics.PorterDuff.Mode.CLEAR); //canvas.drawBitmap(mCacheBitmap, (canvas.getWidth() - mCacheBitmap.getWidth()) / 2, (canvas.getHeight() - mCacheBitmap.getHeight()) / 2, null); //Change to support portrait view Matrix matrix = new Matrix(); matrix.preTranslate((canvas.getWidth() - mCacheBitmap.getWidth()) / 2,(canvas.getHeight() - mCacheBitmap.getHeight()) / 2); if(getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) matrix.postRotate(90f,(canvas.getWidth()) / 2,(canvas.getHeight()) / 2); canvas.drawBitmap(mCacheBitmap, matrix, new Paint()); 

    … Fondamentalmente, questo solo roatates l'image di input come così

    immagine di ingresso ruotata 90

    Questo è meglio, ma ovviamente voglio che questo sia schermo integer.

  • Perché viene visualizzato un errore di accesso illegale quando eseguo i test Android?
  • Fai popup del tasto premuto in una tastiera personalizzata
  • android cambia colore di text degli articoli in filettatura
  • Disegnabile vs Bitmap
  • Posiziona il video all'interno di un VideoView
  • Più frammenti, setRetainInstance (true) e rotazione dello schermo
  • 12 Solutions collect form web for “Ruota l'anteprima della telecamera in Ritratto Android OpenCV Camera”

    in realtà, è ansible eseguire solo la math di width o altezza (full screen).

     if (canvas != null) { canvas.rotate(90,0,0); scale = canvas.getWidth() / (float)bitmap.getHeight(); float scale2 = canvas.getHeight() / (float)bitmap.getWidth(); if(scale2 > scale){ scale = scale2; } if (scale != 0) { canvas.scale(scale, scale,0,0); } canvas.drawBitmap(bitmap, 0, -bitmap.getHeight(), null); 

    Inoltre, è ansible rendere la dimensione di anteprima più grande dello schermo. Solo modificare la scala.

    Ho avuto lo stesso problema cercando di implementare OpenCV. Sono stato in grado di risolvere il problema effettuando le seguenti modifiche al metodo deliverAndDrawFrame.

    1. Ruotare l'object canvas

       Canvas canvas = getHolder().lockCanvas(); // Rotate canvas to 90 degrees canvas.rotate(90f, canvas.getWidth()/2, canvas.getHeight()/2); 
    2. Ridimensionare la bitmap per adattarsi a tutta la dimensione della canvas prima del disegno

       // Resize Bitmap bitmap = Bitmap.createScaledBitmap(mCacheBitmap, canvas.getHeight(), canvas.getWidth(), true); // Use bitmap instead of mCacheBitmap canvas.drawBitmap(bitmap, new Rect(0,0,bitmap.getWidth(), bitmap.getHeight()), new Rect((int)((canvas.getWidth() - mScale*bitmap.getWidth()) / 2),(int)((canvas.getHeight() - mScale*bitmap.getHeight()) / 2),(int)((canvas.getWidth() - mScale*bitmap.getWidth()) / 2 + mScale*bitmap.getWidth()), (int ((canvas.getHeight() - mScale*bitmap.getHeight()) / 2 + mScale*bitmap.getHeight())), null); 

    Ho modificato la CameraBridgeViewBase.java come segue:

     protected Size calculateCameraFrameSize(List<?> supportedSizes, ListItemAccessor accessor, int surfaceWidth, int surfaceHeight) { int calcWidth = 0; int calcHeight = 0; if(surfaceHeight > surfaceWidth){ int temp = surfaceHeight; surfaceHeight = surfaceWidth; surfaceWidth = temp; } 

    E nella function "deliverAndDrawFrame":

      if (mScale != 0) { if(canvas.getWidth() > canvas.getHeight()) { canvas.drawBitmap(mCacheBitmap, new Rect(0,0,mCacheBitmap.getWidth(), mCacheBitmap.getHeight()), new Rect((int)((canvas.getWidth() - mScale*mCacheBitmap.getWidth()) / 2), (int)((canvas.getHeight() - mScale*mCacheBitmap.getHeight()) / 2), (int)((canvas.getWidth() - mScale*mCacheBitmap.getWidth()) / 2 + mScale*mCacheBitmap.getWidth()), (int)((canvas.getHeight() - mScale*mCacheBitmap.getHeight()) / 2 + mScale*mCacheBitmap.getHeight())), null); } else { canvas.drawBitmap(mCacheBitmap, rotateMe(canvas, mCacheBitmap), null); } 

    where rotateMe è definito come segue:

     private Matrix rotateMe(Canvas canvas, Bitmap bm) { // TODO Auto-generated method stub Matrix mtx=new Matrix(); float scale = (float) canvas.getWidth() / (float) bm.getHeight(); mtx.preTranslate((canvas.getWidth() - bm.getWidth())/2, (canvas.getHeight() - bm.getHeight())/2); mtx.postRotate(90,canvas.getWidth()/2, canvas.getHeight()/2); mtx.postScale(scale, scale, canvas.getWidth()/2 , canvas.getHeight()/2 ); return mtx; } 

    L'FPS di anteprima è più lento perché per il sovraccarico computazionale se confrontato con la modalità orizzontale.

    Sfortunatamente Opencv4Android non support la camera ritratta. Ma c'è un modo per superarla. 1) Scrivi la camera personalizzata e imposta l'orientamento in ritratto. 2) Registrarsi per il suo richiamo di anteprima. 3) In onPreviewFrame(byte[]data, Camera camera) crea Mat di byte di anteprima:

     Mat mat = new Mat(previewSize.height, previewSize.width, CvType.CV_8UC1); mat.put(0, 0, data); Core.transpose(mat, mat); Core.flip(mat, mat, -1); // rotates Mat to portrait 

    CvType dipende da un formato di anteprima che utilizza la camera.

    PS. non dimenticare di rilasciare tutte le istanze di Mat che hai creato quando hai finito.

    PPS. è bene gestire la camera su un thread separato per non sovraccaricare il thread UI durante una ricerca.

    Sembra che la nuova class OpenCV CameraBridgeViewBase.java sia troppo elevata e non fornisce un sufficiente controllo sul layout dell'anteprima della telecamera. Date un'occhiata al mio codice di esempio , basato su alcuni dei campioni di OpenCV più vecchi e utilizza codice Android puro. Per utilizzare l'arrays byte passato in onPreviewFrame , put() in un Mat e convertire da YUV a RGB:

     mYuv = new Mat(previewHeight + previewHeight/2, previewWidth, CvType.CV_8UC1); mYuv.put(0, 0, mBuffer); Imgproc.cvtColor(mYuv, mRgba, Imgproc.COLOR_YUV420sp2RGBA, 4); 

    Potresti essere in grado di trovare i vecchi campioni OpenCV4Android su internet, anche se sono stati scaricati alcune versioni precedenti. Tuttavia, il codice campione collegato e lo snippet di cui sopra dovrebbe essere sufficiente per iniziare.

    Se stai utilizzando l'openCV 2.4.9, provare: 1) copiare il contenuto di opencv tutorial-mixed processing nel tuo codice; 2) correggere gli errori di non corrispondenza (nome dell'attività e probabilmente riferimento layout); 3) Modifica il tuo manifesto aggiungendo android:screenOrientation ="landscape" 4) correggere errori minori e correre !!!! bbaamm (dovrebbe funzionare correttamente ora)

    Nota: con questo metodo la barra di stato appare sul lato destro quando il telefono è in posizione verticale. Dal momento che stiamo sviluppando il progetto della camera, ti consiglio di rimuovere la barra di stato dall'anteprima.

    Spero che sia d'aiuto !!!

    Tutte le risposte qui sono hack. Preferisco questa soluzione:

    modifica nel codice JavaCameraView:

     mBuffer = new byte[size]; mCamera.setDisplayOrientation(90); //add this mCamera.addCallbackBuffer(mBuffer); 

    Secondo cambiamento:

     // if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { // mSurfaceTexture = new SurfaceTexture(MAGIC_TEXTURE_ID); // mCamera.setPreviewTexture(mSurfaceTexture); // } else // mCamera.setPreviewDisplay(null); mCamera.setPreviewDisplay(getHolder()); 

    Ho avuto l'orientamento verticale con CameraBridgeViewBase, ma ho dovuto cambiare JavaCameraView.java all'interno dell'OpenCV 🙁 L'idea è la prossima: dopo la macchina fotografica init, fare il prossimo

     setDisplayOrientation(mCamera, 90); mCamera.setPreviewDisplay(getHolder()); 

    e il metodo setDisplayOrientation

     protected void setDisplayOrientation(Camera camera, int angle){ Method downPolymorphic; try { downPolymorphic = camera.getClass().getMethod("setDisplayOrientation", new Class[] { int.class }); if (downPolymorphic != null) downPolymorphic.invoke(camera, new Object[] { angle }); } catch (Exception e1) { } } 

    Devi considerare alcune cose:

    • onPreviewFrame () fornisce sempre i dati della macchina fotografica raw nella sua rotazione assombled
    • getSupportedPreviewSizes () fornisce rapporti di aspetto corrispondenti
    • L'algorithm ha bisogno di analizzare il ritratto in ritratto per rilevare gli oggetti corretti.
    • la Bitmap creata (lato Java) per memorizzare il fotogramma risultante ha anche bisogno del rapporto di aspetto corretto

    Quindi, per una soluzione veloce e ad alta risoluzione ho cambiato JavaCameraView.java e la mia parte JNI. in JavaCameraView.java:

     ... if (sizes != null) { /* Select the size that fits surface considering maximum size allowed */ Size frameSize; if(width > height) { frameSize = calculateCameraFrameSize(sizes, new JavaCameraSizeAccessor(), width, height); }else{ frameSize = calculateCameraFrameSize(sizes, new JavaCameraSizeAccessor(), height, width); } ... mCamera.setParameters(params); params = mCamera.getParameters(); int bufFrameWidth, bufFrameHeight; bufFrameWidth = params.getPreviewSize().width; bufFrameHeight = params.getPreviewSize().height; if(width > height) { mFrameWidth = params.getPreviewSize().width; mFrameHeight = params.getPreviewSize().height; }else{ mFrameWidth = params.getPreviewSize().height; mFrameHeight = params.getPreviewSize().width; } ... mFrameChain = new Mat[2]; mFrameChain[0] = new Mat(bufFrameHeight + (bufFrameHeight/2), bufFrameWidth, CvType.CV_8UC1); mFrameChain[1] = new Mat(bufFrameHeight + (bufFrameHeight/2), bufFrameWidth, CvType.CV_8UC1); AllocateCache(); mCameraFrame = new JavaCameraFrame[2]; mCameraFrame[0] = new JavaCameraFrame(mFrameChain[0], bufFrameWidth, bufFrameHeight); mCameraFrame[1] = new JavaCameraFrame(mFrameChain[1], bufFrameWidth, bufFrameHeight); 

    Con questi cambiamenti, abbiamo fatto in modo di utilizzare il risultato più alto disponibile per il ritratto (switches height / width in calculateCameraFrameSize). Stiamo ancora gestendo il paesaggio come input da onPreviewFrame () ma abbiamo creato una Bitmap per disegnare il ritratto (AllocateCache).

    Infine, dobbiamo dare all'algorithm il ritratto-frame per consentirgli di rilevare oggetti "in piedi" e di restituirlo per il salvataggio e la rappresentazione della bitmap. Quindi, seguendo le modifiche alla tua attività:

     public Mat rot90(Mat matImage, int rotflag){ //1=CW, 2=CCW, 3=180 Mat rotated = new Mat(); if (rotflag == 1){ rotated = matImage.t(); flip(rotated, rotated, 1); //transpose+flip(1)=CW } else if (rotflag == 2) { rotated = matImage.t(); flip(rotated, rotated,0); //transpose+flip(0)=CCW } else if (rotflag ==3){ flip(matImage, rotated,-1); //flip(-1)=180 } else if (rotflag != 0){ //if not 0,1,2,3: Log.e(TAG, "Unknown rotation flag("+rotflag+")"); } return rotated; } public Mat onCameraFrame(CvCameraViewFrame inputFrame) { mRgba = rot90(inputFrame.rgba(), 1); mGray = rot90(inputFrame.gray(), 1); ... 

    La risposta dello sviluppatore "jaiprakashgogi" sta funzionando per me. ma il problema è l'anteprima che viene salvata solo come paesaggio. ciò significa che se abbiamo impostato l'anteprima in immagini, viene visualizzata come un paesaggio.

    La soluzione sopra funziona fino a mostrare l'anteprima come ritratto ma non salvata come ritratto persistente.

    Ho risolto questo problema come segue.

    1. convertire i dati di byte o matte in bitmap
    2. ruotare la matrix a 90 gradi e applicarsi a bitmap
    3. convertire bitmap in byte arrays e salvarlo.

    per favore vedi il mio codice qui …

      public String writeToSDFile(byte[] data, int rotation){ byte[] portraitData=null; if(rotation==90){ Log.i(TAG,"Rotation is : "+rotation); Bitmap bitmap= BitmapFactory.decodeByteArray(data,0,data.length); Matrix matrix = new Matrix(); matrix.postRotate(90); Bitmap rotatedBitmap = Bitmap.createBitmap(bitmap , 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true); portraitData=bitmapToByte(rotatedBitmap); } File dir=getDirectory(); String imageTime=""+System.currentTimeMillis(); String fileName=Constants.FILE_NAME+imageTime+"."+Constants.IMAGE_FORMAT; File file = new File(dir, fileName); try { FileOutputStream f = new FileOutputStream(file); if(rotation==90){ f.write(portraitData); }else { f.write(data); } f.close(); } catch (FileNotFoundException e) { e.printStackTrace(); Log.i(TAG, "******* File not found. Did you" + " add a WRITE_EXTERNAL_STORAGE permission to the manifest?"); } catch (IOException e) { e.printStackTrace(); } Log.i(TAG,"\n\nFile written to "+file); return fileName; } // convert bitmap to Byte Array public byte[] bitmapToByte(Bitmap bitmap){ ByteArrayOutputStream outputStream=new ByteArrayOutputStream(); bitmap.compress(Bitmap.CompressFormat.JPEG,100,outputStream); byte[] arrays=outputStream.toByteArray(); return arrays; } 

    Risolve completamente il mio problema.

    ho la stessa questione, ho avuto capire! e c'è la mia soluzione:

    come parte di prima, In CameraBridgeViewBase.Java , due costruttori, aggiungere l'initialization di WindowManager:

     public CameraBridgeViewBase(Context context, int cameraId) { super(context); mCameraIndex = cameraId; getHolder().addCallback(this); mMaxWidth = MAX_UNSPECIFIED; mMaxHeight = MAX_UNSPECIFIED; windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); 

    }

     public CameraBridgeViewBase(Context context, AttributeSet attrs) { super(context, attrs); int count = attrs.getAttributeCount(); Log.d(TAG, "Attr count: " + Integer.valueOf(count)); TypedArray styledAttrs = getContext().obtainStyledAttributes(attrs, R.styleable.CameraBridgeViewBase); if (styledAttrs.getBoolean(R.styleable.CameraBridgeViewBase_show_fps, false)) enableFpsMeter(); mCameraIndex = styledAttrs.getInt(R.styleable.CameraBridgeViewBase_camera_id, -1); getHolder().addCallback(this); mMaxWidth = MAX_UNSPECIFIED; mMaxHeight = MAX_UNSPECIFIED; windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); styledAttrs.recycle(); 

    }

    quindi, è necessario sostituire la function deliverAndDrawFrame(CvCameraViewFrame frame) come segue,

     protected void deliverAndDrawFrame(CvCameraViewFrame frame) { Mat modified; if (mListener != null) { modified = mListener.onCameraFrame(frame); } else { modified = frame.rgba(); } boolean bmpValid = true; if (modified != null) { try { Utils.matToBitmap(modified, mCacheBitmap); } catch (Exception e) { Log.e(TAG, "Mat type: " + modified); Log.e(TAG, "Bitmap type: " + mCacheBitmap.getWidth() + "*" + mCacheBitmap.getHeight()); Log.e(TAG, "Utils.matToBitmap() throws an exception: " + e.getMessage()); bmpValid = false; } } if (bmpValid && mCacheBitmap != null) { Canvas canvas = getHolder().lockCanvas(); if (canvas != null) { canvas.drawColor(0, android.graphics.PorterDuff.Mode.CLEAR); int rotation = windowManager.getDefaultDisplay().getRotation(); int degrees = 0; // config degrees as you need switch (rotation) { case Surface.ROTATION_0: degrees = 90; break; case Surface.ROTATION_90: degrees = 0; break; case Surface.ROTATION_180: degrees = 270; break; case Surface.ROTATION_270: degrees = 180; break; } Matrix matrix = new Matrix(); matrix.postRotate(degrees); Bitmap outputBitmap = Bitmap.createBitmap(mCacheBitmap, 0, 0, mCacheBitmap.getWidth(), mCacheBitmap.getHeight(), matrix, true); if (outputBitmap.getWidth() <= canvas.getWidth()) { mScale = getRatio(outputBitmap.getWidth(), outputBitmap.getHeight(), canvas.getWidth(), canvas.getHeight()); } else { mScale = getRatio(canvas.getWidth(), canvas.getHeight(), outputBitmap.getWidth(), outputBitmap.getHeight()); } if (mScale != 0) { canvas.scale(mScale, mScale, 0, 0); } Log.d(TAG, "mStretch value: " + mScale); canvas.drawBitmap(outputBitmap, 0, 0, null); if (mFpsMeter != null) { mFpsMeter.measure(); mFpsMeter.draw(canvas, 20, 30); } getHolder().unlockCanvasAndPost(canvas); } } 

    }

    e aggiungere questa funtion extra,

     private float getRatio(int widthSource, int heightSource, int widthTarget, int heightTarget) { if (widthTarget <= heightTarget) { return (float) heightTarget / (float) heightSource; } else { return (float) widthTarget / (float) widthSource; } 

    }

    è ok, e se questa risposta è utile per te, segna 'accettata' la Reputazione della Guida

    Non è necessario ruotare lo schermo.

    Modificare il file Manifest.xml con la seguente row:

      <activity android:screenOrientation="landscape" android:configChanges="keyboardHidden|orientation|screenSize"> 

    In questo modo verrà visualizzata un'anteprima della telecamera a schermo integer, che funziona allo stesso modo dell'anteprima della telecamera di sistema.

    L'Android è un fan Android di Google, tutto su telefoni Android, Android Wear, Android Dev e applicazioni Android Games e così via.