2014-04-21 2 views
2

30 초 동안 ffmpeg를 사용하여 비디오를 캡처합니다.IplImage 자르기 및 회전 - Android

private class SaveFrame extends AsyncTask<byte[], Void, File> { 
      long t; 
      protected File doInBackground(byte[]... arg) { 

       t = 1000 * (System.currentTimeMillis() - firstTime - pausedTime); 
       toSaveFrames++; 
       File pathCache = new File(Environment.getExternalStorageDirectory()+"/DCIM", (System.currentTimeMillis()/1000L)+ "_" + toSaveFrames + ".tmp"); 
       BufferedOutputStream bos; 
       try { 
        bos = new BufferedOutputStream(new FileOutputStream(pathCache)); 
        bos.write(arg[0]); 
        bos.flush(); 
        bos.close(); 
       } catch (FileNotFoundException e) { 
        e.printStackTrace(); 
        pathCache = null; 
        toSaveFrames--; 
       } catch (IOException e) { 
        e.printStackTrace(); 
        pathCache = null; 
        toSaveFrames--; 
       } 
       return pathCache; 


      } 
      @Override 
      protected void onPostExecute(File filename) 
      { 
       if(filename!=null) 
       { 
        savedFrames++; 
        tempList.add(new FileFrame(t,filename)); 
       } 
      } 
     } 

마침내 내가 작물 및 회전

private class AddFrame extends AsyncTask<Void, Integer, Void> { 
     private int serial = 0; 
     @Override 
     protected Void doInBackground(Void... params) { 

      for(int i=0; i<tempList.size(); i++) 
      { 
       byte[] bytes = new byte[(int) tempList.get(i).file.length()]; 
       try { 
        BufferedInputStream buf = new BufferedInputStream(new FileInputStream(tempList.get(i).file)); 
        buf.read(bytes, 0, bytes.length); 
        buf.close(); 

        IplImage image = IplImage.create(imageWidth, imageHeight, IPL_DEPTH_8U, 2); 

//          final int startY = 640*(480-480)/2; 
//          final int lenY = 640*480; 
//          yuvIplimage.getByteBuffer().put(bytes, startY, lenY); 
//          final int startVU = 640*480+ 640*(480-480)/4; 
//          final int lenVU = 640* 480/2; 
//          yuvIplimage.getByteBuffer().put(bytes, startVU, lenVU); 

        if (tempList.get(i).time > recorder.getTimestamp()) { 
         recorder.setTimestamp(tempList.get(i).time); 
        } 

        image = cropImage(image); 
        image = rotate(image, 270); 
//          image = rotateImage(image); 
        recorder.record(image); 
        Log.i(LOG_TAG, "record " + i); 
        image = null; 
        serial++; 
        publishProgress(serial); 
       } catch (FileNotFoundException e) { 
        e.printStackTrace(); 
       } catch (IOException e) { 
        e.printStackTrace(); 
       } catch (com.googlecode.javacv.FrameRecorder.Exception e) { 
        e.printStackTrace(); 
       } 
      } 
      return null; 
     } 
     @Override 
     protected void onProgressUpdate(Integer... serial) { 
      int value = serial[0]; 
      creatingProgress.setProgress(value); 
     } 
     @Override 
     protected void onPostExecute(Void v) 
     { 
      creatingProgress.dismiss(); 
      if (recorder != null && recording) { 
       recording = false; 
       Log.v(LOG_TAG,"Finishing recording, calling stop and release on recorder"); 
       try { 
        recorder.stop(); 
        recorder.release(); 
        finish(); 
        startActivity(new Intent(RecordActivity.this,AnswerViewActivity.class)); 
       } catch (FFmpegFrameRecorder.Exception e) { 
        e.printStackTrace(); 
       } 
       recorder = null; 
      } 
     } 
    } 

내 작물로 모든 프레임을 추가하고

private IplImage cropImage(IplImage src) 
    { 
     cvSetImageROI(src, r); 
     IplImage cropped = IplImage.create(imageHeight, imageHeight, IPL_DEPTH_8U, 2); 
     cvCopy(src, cropped); 
     return cropped; 
    } 

    public static IplImage rotate(IplImage image, double angle) {   
     IplImage copy = opencv_core.cvCloneImage(image); 

     IplImage rotatedImage = opencv_core.cvCreateImage(opencv_core.cvGetSize(copy), copy.depth(), copy.nChannels()); 
     CvMat mapMatrix = opencv_core.cvCreateMat(2, 3, opencv_core.CV_32FC1); 

     //Define Mid Point 
     CvPoint2D32f centerPoint = new CvPoint2D32f(); 
     centerPoint.x(copy.width()/2); 
     centerPoint.y(copy.height()/2); 

     //Get Rotational Matrix 
     opencv_imgproc.cv2DRotationMatrix(centerPoint, angle, 1.0, mapMatrix); 

     //Rotate the Image 
     opencv_imgproc.cvWarpAffine(copy, rotatedImage, mapMatrix, opencv_imgproc.CV_INTER_CUBIC + opencv_imgproc.CV_WARP_FILL_OUTLIERS, opencv_core.cvScalarAll(170)); 
     opencv_core.cvReleaseImage(copy); 
     opencv_core.cvReleaseMat(mapMatrix);   
     return rotatedImage; 
    } 

아래에있는 방법을 회전 아래 프레임 클래스 저장

@Override 
     public void onPreviewFrame(byte[] data, Camera camera) { 
      if (yuvIplimage != null && recording && rec) 
       { 
        new SaveFrame().execute(data); 
       } 
      } 
     } 

은 내 최종 비디오 자르기 및 부패 먹었지 만 녹색 프레임과 색이 칠해진 프레임은 이것과 섞였다.

이 문제를 해결하는 방법. 나는 iplimage를 알지 못한다. 일부 블로그에서는 YUV 형식을 언급합니다. 먼저 Y를 변환 한 다음 UV를 변환해야합니다.

이 문제를 해결하는 방법은 무엇입니까?

+0

해결책을 얻었습니까? – intrepidkarthi

+0

이미지를 회전하면 이미지 크기가 너비와 높이에서 증가/감소합니다. 기록계.기록 (이미지); 레코더 초기화 시간에 제공된 너비와 높이가 필요합니다. –

답변

2

캡처 한 프레임의 조 변경 및 크기 조정을 위해 Open Source Android Touch-To-Record library의 onPreviewFrame 메서드를 수정했습니다.

내 setCameraParams() 메소드에서 다음과 같이 "yuvIplImage"를 정의했습니다.

IplImage yuvIplImage = IplImage.create(mPreviewSize.height, mPreviewSize.width, opencv_core.IPL_DEPTH_8U, 2); 

또한 그 반대의 경우도 마찬가지, 다음과 같은 높이와 폭을주고로 videoRecorder 객체를 초기화합니다. 이 코드는 해결하는 데 사용됩니다 나는 기본적으로이 link

이 방법에서 발견하는 방법 "YUV_NV21_TO_BGR"를 사용

@Override 
public void onPreviewFrame(byte[] data, Camera camera) 
{ 

    long frameTimeStamp = 0L; 

    if(FragmentCamera.mAudioTimestamp == 0L && FragmentCamera.firstTime > 0L) 
    { 
     frameTimeStamp = 1000L * (System.currentTimeMillis() - FragmentCamera.firstTime); 
    } 
    else if(FragmentCamera.mLastAudioTimestamp == FragmentCamera.mAudioTimestamp) 
    { 
     frameTimeStamp = FragmentCamera.mAudioTimestamp + FragmentCamera.frameTime; 
    } 
    else 
    { 
     long l2 = (System.nanoTime() - FragmentCamera.mAudioTimeRecorded)/1000L; 
     frameTimeStamp = l2 + FragmentCamera.mAudioTimestamp; 
     FragmentCamera.mLastAudioTimestamp = FragmentCamera.mAudioTimestamp; 
    } 

    synchronized(FragmentCamera.mVideoRecordLock) 
    { 
     if(FragmentCamera.recording && FragmentCamera.rec && lastSavedframe != null && lastSavedframe.getFrameBytesData() != null && yuvIplImage != null) 
     { 
      FragmentCamera.mVideoTimestamp += FragmentCamera.frameTime; 

      if(lastSavedframe.getTimeStamp() > FragmentCamera.mVideoTimestamp) 
      { 
       FragmentCamera.mVideoTimestamp = lastSavedframe.getTimeStamp(); 
      } 

      try 
      { 
       yuvIplImage.getByteBuffer().put(lastSavedframe.getFrameBytesData()); 

       IplImage bgrImage = IplImage.create(mPreviewSize.width, mPreviewSize.height, opencv_core.IPL_DEPTH_8U, 4);// In my case, mPreviewSize.width = 1280 and mPreviewSize.height = 720 
       IplImage transposed = IplImage.create(mPreviewSize.height, mPreviewSize.width, yuvIplImage.depth(), 4); 
       IplImage squared = IplImage.create(mPreviewSize.height, mPreviewSize.height, yuvIplImage.depth(), 4); 

       int[] _temp = new int[mPreviewSize.width * mPreviewSize.height]; 

       Util.YUV_NV21_TO_BGR(_temp, data, mPreviewSize.width, mPreviewSize.height); 

       bgrImage.getIntBuffer().put(_temp); 

       opencv_core.cvTranspose(bgrImage, transposed); 
       opencv_core.cvFlip(transposed, transposed, 1); 

       opencv_core.cvSetImageROI(transposed, opencv_core.cvRect(0, 0, mPreviewSize.height, mPreviewSize.height)); 
       opencv_core.cvCopy(transposed, squared, null); 
       opencv_core.cvResetImageROI(transposed); 

       videoRecorder.setTimestamp(lastSavedframe.getTimeStamp()); 
       videoRecorder.record(squared); 
      } 
      catch(com.googlecode.javacv.FrameRecorder.Exception e) 
      { 
       e.printStackTrace(); 
      } 
     } 

     lastSavedframe = new SavedFrames(data, frameTimeStamp); 
    } 
} 

:

//call initVideoRecorder() method like this to initialize videoRecorder object of FFmpegFrameRecorder class. 
initVideoRecorder(strVideoPath, mPreview.getPreviewSize().height, mPreview.getPreviewSize().width, recorderParameters); 

//method implementation 
public void initVideoRecorder(String videoPath, int width, int height, RecorderParameters recorderParameters) 
{ 
    Log.e(TAG, "initVideoRecorder"); 

    videoRecorder = new FFmpegFrameRecorder(videoPath, width, height, 1); 
    videoRecorder.setFormat(recorderParameters.getVideoOutputFormat()); 
    videoRecorder.setSampleRate(recorderParameters.getAudioSamplingRate()); 
    videoRecorder.setFrameRate(recorderParameters.getVideoFrameRate()); 
    videoRecorder.setVideoCodec(recorderParameters.getVideoCodec()); 
    videoRecorder.setVideoQuality(recorderParameters.getVideoQuality()); 
    videoRecorder.setAudioQuality(recorderParameters.getVideoQuality()); 
    videoRecorder.setAudioCodec(recorderParameters.getAudioCodec()); 
    videoRecorder.setVideoBitrate(1000000); 
    videoRecorder.setAudioBitrate(64000); 
} 

내 onPreviewFrame() 메소드입니다 나는 당신과 마찬가지로 "The Green Devil problem in Android"으로 전화를 걸었습니다. 나는 같은 문제가 있었고 거의 3-4 일을 낭비했다. YuvIplImage의 전치를 가져 왔을 때 "YUV_NV21_TO_BGR"메서드를 추가하기 전에, 더 중요한 것은 전치, 뒤집기 (또는 크기 조정없이)의 조합이 결과 비디오에 인 녹색 출력 이었습니다. 이 "YUV_NV21_TO_BGR"메소드는 요일을 저장했습니다. Google 그룹스 스레드 위의 @David Han 덕분입니다.

또한 onPreviewFrame의 모든 처리 (조옮김, 뒤집기 및 크기 조정)에 많은 시간이 걸리므로 초당 프레임 속도 (FPS)에서 매우 심각한 오류가 발생합니다. 이 코드를 사용할 때 onPreviewFrame 메서드 내에서 기록 된 비디오의 결과 FPS는 30fps에서 3 프레임/초로 떨어졌습니다.

이 방법을 사용하지 말 것을 권합니다. 대신 AsyncTask에서 JavaCV를 사용하여 비디오 파일의 사후 레코딩 처리 (조 변경, 뒤집기 및 크기 조정)를 수행 할 수 있습니다. 희망이 도움이됩니다.

0
@Override 
public void onPreviewFrame(byte[] data, Camera camera) { 
    //IplImage newImage = cvCreateImage(cvGetSize(yuvIplimage), IPL_DEPTH_8U, 1); 
    if (recording) {  
     videoTimestamp = 1000 * (System.currentTimeMillis() - startTime);     
     yuvimage = IplImage.create(imageWidth, imageHeight * 3/2, IPL_DEPTH_8U,1); 
     yuvimage.getByteBuffer().put(data); 

     rgbimage = IplImage.create(imageWidth, imageHeight, IPL_DEPTH_8U, 3); 
     opencv_imgproc.cvCvtColor(yuvimage, rgbimage, opencv_imgproc.CV_YUV2BGR_NV21);  

     IplImage rotateimage=null; 
       try { 
        recorder.setTimestamp(videoTimestamp); 
        int rot=0; 
        switch (degrees) { 
        case 0: 
         rot =1; 
         rotateimage=rotate(rgbimage,rot); 
        break; 
        case 180: 
         rot = -1; 
         rotateimage=rotate(rgbimage,rot); 
         break;      
        default: 
         rotateimage=rgbimage; 
       }      
        recorder.record(rotateimage); 

       } catch (FFmpegFrameRecorder.Exception e) { 
       e.printStackTrace(); 
       } 
     } 

    } 
IplImage rotate(IplImage IplSrc,int angle) { 
    IplImage img= IplImage.create(IplSrc.height(), IplSrc.width(), IplSrc.depth(), IplSrc.nChannels()); 
    cvTranspose(IplSrc, img); 
    cvFlip(img, img, angle);   
    return img; 
    }  
} 

많은 검색 후이 작품이 나를 위해 작동합니다.

+0

@topcpl 줄 번호에 오류가 발생했습니다. opencv_imgproc.cvCvtColor (yuvimage, rgbimage, opencv_imgproc.CV_YUV2BGR_NV21); – Saty

관련 문제