【问题标题】:Data Timestamp Android数据时间戳安卓
【发布时间】:2017-10-08 19:22:53
【问题描述】:

我正在开发一个应用程序,我可以在其中进行一些实时图像处理。在我的相机视图中,我在 onPreviewFrame 内进行图像处理,其中我循环遍历每个像素,然后找到每个帧的总和 Y 值。然后我将其保存到 csv 文件中,一切正常。除此之外,我还想存储 csv 中每帧之间经过的时间以及每个 y-sum。

图像处理

public abstract class ImageProcessing {

 public static int YUV420SPtoYSum(byte[] yuv420sp, int width, int height){

    if(yuv420sp == null)
        return 0;

    int sum = 0;
    final int ii = 0;
    final int ij = 0;
    final int di = +1;
    final int dj = +1;
    int y = 0;
    for (int i = 0, ci = ii; i < height; ++i, ci += di) {
        for (int j = 0, cj = ij; j < width; ++j, cj += dj) {
            y = (0xff & ((int) yuv420sp[ci * width + cj]));
            //y = y < 16 ? 16 : y;

            sum += y;
        }
    }
  return sum;
 }
}

CameraView 类

public class CameraView extends SurfaceView implements SurfaceHolder.Callback, Camera.PreviewCallback {

private static final String TAG = "CameraView";
Camera.Size mPreviewSize;
List<Camera.Size> mSupportedPreviewSizes;
private SurfaceHolder mHolder;
private Camera mCamera;
int img_Y_Avg, img_U_Avg, img_V_Avg;


public interface PreviewReadyCallback {
    void onPreviewFrame(int yAverage, int uAverage, int vAverage); // Any value you want to get
}

PreviewReadyCallback mPreviewReadyCallback = null;

public void setOnPreviewReady(PreviewReadyCallback cb) {
    mPreviewReadyCallback = cb;
}



public CameraView(Context context, Camera camera){
    super(context);
    mCamera = camera;

    //mCamera.setDisplayOrientation(90);
    mSupportedPreviewSizes = mCamera.getParameters().getSupportedPreviewSizes();
    for(Camera.Size str: mSupportedPreviewSizes)
        Log.e(TAG, str.width + "/" + str.height);

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

@Override
public void surfaceCreated(SurfaceHolder surfaceHolder){
    try{
        mCamera.setPreviewDisplay(surfaceHolder);
        mCamera.startPreview();
    }catch(Exception e){
        Log.d("ERROR","Camera error on SurfaceCreated" + e.getMessage());
    }
}

@Override
public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i2, int i3) {

    if(mHolder.getSurface() == null)
        return;
    try{
        mCamera.stopPreview();
    }catch(Exception e) {
        Log.d("ERROR","Camera error on SurfaceChanged" + e.getMessage());
    }
    try {
        Camera.Parameters parameters = mCamera.getParameters();

        parameters.setPreviewSize(176, 144);
        mCamera.cancelAutoFocus();
        //parameters.setAutoExposureLock(false);
        mCamera.setDisplayOrientation(90);
        //set fps
        parameters.setPreviewFpsRange(16000, 16000);
        //on flash
        parameters.setFlashMode(parameters.FLASH_MODE_AUTO);
        //parameters.setAutoWhiteBalanceLock(true);
        parameters.setPreviewFormat(ImageFormat.NV21);

        /*if (parameters.getMaxNumMeteringAreas() > 0){ // check that metering areas are supported
            List<Camera.Area> meteringAreas = new ArrayList<Camera.Area>();

            Rect areaRect1 = new Rect(-50, -50, 50, 50);    // specify an area in center of image
            meteringAreas.add(new Camera.Area(areaRect1, 1000)); // set weight to 60%
            parameters.setMeteringAreas(meteringAreas);
        }*/



        //mCamera.setDisplayOrientation(90);
        mCamera.setParameters(parameters);
        mCamera.setPreviewDisplay(mHolder);
        mCamera.setPreviewCallback(this);
        mCamera.startPreview();

    } catch (IOException e) {
        Log.d("ERROR","Camera error on SurfaceChanged" + e.getMessage());
    }
}



@Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
    if (mCamera != null){
        //mCamera.stopPreview();
        //mCamera.release();
    }

}

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

    //check if data is null
    if (data == null)
        throw new NullPointerException();

    Camera.Size size = camera.getParameters().getPreviewSize();

    //check if size is null
    if(size == null)
        throw new NullPointerException();


    //set resolution of camera view to optimal setting
    int width = size.width;
    int height = size.height;
    Log.d("Resolution ", " "+String.valueOf(width)+" "+String.valueOf(height));

    //call ImageProcess on the data to decode YUV420SP to RGB
    img_Y_Avg = ImageProcessing.YUV420SPtoYSum(data, width, height);
    img_U_Avg = ImageProcessing.YUV420SPtoUSum(data, width, height);
    img_V_Avg = ImageProcessing.YUV420SPtoVSum(data, width, height);

    mPreviewReadyCallback.onPreviewFrame(img_Y_Avg, img_U_Avg, img_V_Avg);

}




@Override
protected  void onMeasure(int widthMeasureSpec, int heightMeasureSpec){
    final int width = resolveSize(getSuggestedMinimumWidth(),widthMeasureSpec);
    final int height = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec);
    setMeasuredDimension(width, height);

    if(mSupportedPreviewSizes != null){
        mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, width, height);
        Log.d("Resolution ", " "+mPreviewSize);
    }
}


private Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, int w, int h){
    final double ASPECT_TOLERANCE = 0.1;
    double targetRatio = (double) h / w;

    if (sizes == null) return null;

    Camera.Size optimalSize = null;
    double minDiff = Double.MAX_VALUE;

    int targetHeight = h;

    for (Camera.Size size : sizes){
        double ratio = (double) size.width  / size.height;
        if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) continue;
        if (Math.abs(size.height - targetHeight) < minDiff){
            optimalSize = size;
            minDiff = Math.abs(size.height - targetHeight);
        }
    }

    if (optimalSize == null){
        minDiff = Double.MIN_VALUE;
        for (Camera.Size size : sizes){
            if (Math.abs(size.height - targetHeight) < minDiff){
                optimalSize = size;
                minDiff = Math.abs(size.height - targetHeight);
            }
        }
    }
    return optimalSize;
}
}

MainActivity

public class MainActivity extends AppCompatActivity implements CameraView.PreviewReadyCallback {
private static Camera camera = null;
private CameraView image = null;

private LineChart bp_graph;
private static int img_Y_Avg = 0, img_U_Avg = 0, img_V_Avg = 0;
double valueY, valueU, valueV;
Handler handler;
private int readingRemaining = 600;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);

    bp_graph = (LineChart)findViewById(R.id.graph);


    graph_features();

    //open camera
    try {
        camera = Camera.open();

        handler = new Handler();
        final Runnable runnable = new Runnable() {
            @Override
            public void run() {
                camera.stopPreview();
                camera.release();
            }
        };
        handler.postDelayed(runnable, 30000);

    } catch (Exception e) {
        Log.d("ERROR", "Failed to get camera: " + e.getMessage());
    }

    if (camera != null) {
        image = new CameraView(this, camera);
        FrameLayout camera_view = (FrameLayout) findViewById(R.id.camera_view);
        camera_view.addView(image);
        image.setOnPreviewReady(this);
    }

    //close camera button
    ImageButton imgClose = (ImageButton) findViewById(R.id.imgClose);
    imgClose.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            System.exit(0);
        }
    });

}


@Override
protected void onResume(){
    super.onResume();
}

@Override
protected void onPause() {
    super.onPause();
}

private void graph_features(){
    bp_graph.getDescription().setEnabled(false);


    //enable touch gesture
    bp_graph.setTouchEnabled(true);

    //enable scaling
    bp_graph.setDragEnabled(true);

    //scale and drag
    bp_graph.setScaleEnabled(true);
    bp_graph.setDrawGridBackground(false);

    //enable pinch zoom in
    bp_graph.setPinchZoom(true);

    //alternative background color
    bp_graph.setBackgroundColor(Color.LTGRAY);

    //work on data
    LineData lineData = new LineData();
    lineData.setValueTextColor(Color.WHITE);

    //add data to line chart
    bp_graph.setData(lineData);

    //animate
    bp_graph.animateX(600);

    Legend legend = bp_graph.getLegend();

    //custom legend
    legend.setForm(Legend.LegendForm.LINE);
    legend.setTextColor(Color.WHITE);

    XAxis x1 = bp_graph.getXAxis();
    x1.setTextColor(Color.WHITE);
    x1.setDrawGridLines(false);
    x1.setAvoidFirstLastClipping(true);
    x1.setPosition(XAxis.XAxisPosition.BOTTOM);

    YAxis y1 = bp_graph.getAxisLeft();
    y1.setTextColor(Color.WHITE);


    y1.setAxisMaximum(5000000);
    y1.setAxisMinimum(100000);
    y1.setDrawGridLines(true);
    //y1.setInverted(true);

    YAxis y2 = bp_graph.getAxisRight();
    y2.setEnabled(false);
}


//method to create set
  private ILineDataSet createSet() {
      LineDataSet set = new LineDataSet(null, "PPG");

      set.setLineWidth(1.0f);
      set.setCircleRadius(1.0f);
      set.setColor(Color.rgb(240, 99, 99));
      set.setCircleColor(Color.rgb(240, 99, 99));
      set.setHighLightColor(Color.rgb(190, 190, 190));
      set.setAxisDependency(YAxis.AxisDependency.LEFT);
      set.setValueTextSize(1.0f);
      return set;
}

@Override
public void onPreviewFrame(int ySum, int uSum, int vSum) {
    img_Y_Avg = ySum;
    img_U_Avg = uSum;
    img_V_Avg = vSum;

    //set value of Y on the text view
    TextView valueOfY = (TextView)findViewById(R.id.valueY);
    valueY = img_Y_Avg;
    valueOfY.setText(Double.toString(img_Y_Avg));

    //set value of U on the text view
    TextView valueOfU = (TextView)findViewById(R.id.valueU);
    valueU = img_U_Avg;
    valueOfU.setText(Double.toString(img_U_Avg));

    //set value of V on the text view
    TextView valueOfV = (TextView)findViewById(R.id.valueV);
    valueV = img_V_Avg;
    valueOfV.setText(Double.toString(img_V_Avg));

    //store value to array list
    ArrayList<Integer> yAverage = new ArrayList<Integer>();
    yAverage.add(img_Y_Avg);
    //Log.d("MyEntryData", String.valueOf(yAverage));

    //store u values to array
    ArrayList<Integer> uAverage = new ArrayList<Integer>();
    uAverage.add(img_U_Avg);
    //Log.d("MyEntryData", String.valueOf(uAverage));

    //store u values to array
    ArrayList<Integer> vAverage = new ArrayList<Integer>();
    vAverage.add(img_V_Avg);
    //Log.d("MyEntryData", String.valueOf(vAverage));

    float start = System.nanoTime();
    int diff = (int) ((System.currentTimeMillis()/1000) - start);

    ArrayList<Integer> difference = new ArrayList<Integer>();
    difference.add(diff);

    Log.d("time", String.valueOf(start));


    ArrayList<Integer> getValues = new ArrayList<Integer>();
    for(int i = 0; i < uAverage.size(); i++) {
        //getValues.add(difference.get(i));
        getValues.add(yAverage.get(i));
        getValues.add(uAverage.get(i));
        getValues.add(vAverage.get(i));
    }


    String filename = new SimpleDateFormat("yyyyMMddHHmm'.csv'").format(new Date());

    File directoryDownload = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
    File logDir = new File (directoryDownload, "bpReader"); //Creates a new folder in DOWNLOAD directory
    logDir.mkdirs();
    File file = new File(logDir, filename);

    FileOutputStream outputStream = null;
    try {
           outputStream = new FileOutputStream(file, true);
           //outputStream = openFileOutput(filename, Context.MODE_PRIVATE);
           for (int i = 0; i < uAverage.size(); i += 3) {
               //outputStream.write((getValues.get(i) + ",").getBytes());
               outputStream.write((getValues.get(i) + ",").getBytes());
               outputStream.write((getValues.get(i + 1) + ",").getBytes());
               outputStream.write((getValues.get(i + 2) + "\n").getBytes());

            }
            outputStream.close();
        } catch (Exception e) {
            e.printStackTrace();
        }

    Log.d("MyEntryData", String.valueOf(getValues));


    handler = new Handler();
    final Runnable runnable = new Runnable() {
        @Override
        public void run() {
            readingRemaining = readingRemaining -1;

            if (readingRemaining > 0){
                plotGraph(img_Y_Avg);
                //plotGraph(img_U_Avg);
                //plotGraph(img_V_Avg);
            }
        }
    };

    handler.postDelayed(runnable, 100);

    //Log.d("MyEntryData", String.valueOf(img_Y_Avg +" "+ img_U_Avg+" "+img_V_Avg));

}

private void plotGraph(double graph_data){
    LineData data = bp_graph.getData();
    if (data != null){
        ILineDataSet set = data.getDataSetByIndex(0);

        if (set == null){
            set = createSet();
            data.addDataSet(set);
        }

        //add a new value
        int randomDataSetIndex = (int) (Math.random() * data.getDataSetCount());
        float yValue = (float)  graph_data;


        data.addEntry(new Entry(data.getDataSetByIndex(randomDataSetIndex).getEntryCount(), yValue), randomDataSetIndex);

        //notify chart data have changed
        bp_graph.notifyDataSetChanged();

        bp_graph.setVisibleXRangeMaximum(100);

        //scroll to last entry
        bp_graph.moveViewTo(data.getEntryCount() - 7, 50f, YAxis.AxisDependency.RIGHT);
    }
}}

我在CameraView 类中进行图像处理,然后借助接口将值发送到MainActivity,在此我生成.csv 文件和图形。 我如何获得正在生成的每一帧(或 2 个连续的 y-sum)之间的时间差?

【问题讨论】:

    标签: android csv image-processing timestamp


    【解决方案1】:

    像这样:

    long startTime = System.currentTimeMillis();
    
    img_Y_Avg = ImageProcessing.YUV420SPtoYSum(data, width, height);
    img_U_Avg = ImageProcessing.YUV420SPtoUSum(data, width, height);
    img_V_Avg = ImageProcessing.YUV420SPtoVSum(data, width, height);
    
    long finishTime = System.currentTimeMillis();
    
    
    mPreviewReadyCallback.onPreviewFrame(img_Y_Avg, img_U_Avg, img_V_Avg,finishTime-startTime);
    

    并将这个参数添加到界面中:

    public interface PreviewReadyCallback {
        void onPreviewFrame(int yAverage, int uAverage, int vAverage, long time);
    }
    

    然后像其他值一样将其保存为 CSV...

    更新: 那是你的计算时间。如果你想要帧之间的时间: 上课:

    long oldTime=System.currentTimeMillis();
    

    然后

    img_Y_Avg = ImageProcessing.YUV420SPtoYSum(data, width, height);
    img_U_Avg = ImageProcessing.YUV420SPtoUSum(data, width, height);
    img_V_Avg = ImageProcessing.YUV420SPtoVSum(data, width, height);
    
    long newTime = System.currentTimeMillis();
    
    mPreviewReadyCallback.onPreviewFrame(img_Y_Avg, img_U_Avg, img_V_Avg,newTime-oldTime);
    oldTime=newTime;
    

    【讨论】:

    • 感谢您的回复。我有这个,并且以与获取其他值相同的方式获取 ArrayList 中的值。但是,时间值是 0、1 或 2。
    • nanoTime() 给出了一些值。但是,如果您查看我的代码,我指定了 16 fps 常量,并且在我的日志中每秒生成 16 个值。所以,据我了解,如果我添加特定秒的所有时间差值,我应该得到大约 1 秒。但在这里我得到了大约 0.01 秒。
    • 我尝试了 long durationInMs = TimeUnit.MICROSECONDS.convert(timeElapsed, TimeUnit.NANOSECONDS);在将它存储到数组之前..我仍然得到不正确的值。由于 16fps,每个值应约为 62000 微秒。但我得到了大约 150 - 2000 微秒
    • 更新了答案
    • 谢谢。我实际上是在不久前这样做的,但是有一个问题。仔细观察我发现的日志,连续的 start(i) 和 stop(i) 时间相差 0、1 或 2 毫秒。实际区别在于 stop(i) 和 start(i+1)..... stop(i+1) 和 start(i+2).. 等等。因此,我将开始时间和结束时间都传递给 mainAvticity,将它们存储到两个单独的值中并尝试遍历它们以执行类似 end(i+1) - start(i) 或 end(i+1)-end( i)..
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-06-29
    • 1970-01-01
    • 1970-01-01
    • 2019-03-14
    • 1970-01-01
    • 1970-01-01
    • 2023-01-03
    相关资源
    最近更新 更多