Сканирование каждого пикселя, чтобы получить значения RGB - PullRequest
0 голосов
/ 03 мая 2018

Я хочу получить значения RGB для каждого пикселя во время потоковой передачи видео. В настоящее время я использую textureView для отображения потока камеры. Каждый раз, когда я получаю новый кадр, я сканирую кадр и вижу, все ли значения RG и B равны 255. Но проблема в : сканирование одного кадра занимает более 20 секунд, поэтому он пропускает 30-40 кадров. Я хочу читать пиксели, не пропуская ни одного. Так что, если кто-нибудь может сообщить мне, если есть эффективный способ сделать это, я был бы очень признателен за их помощь.

Вот как я.

TextureView.SurfaceTextureListener textureListener = new TextureView.SurfaceTextureListener() {
    @Override
    public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int i, int i1) {
        openCamera();
    }

    @Override
    public void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture, int i, int i1) {

    }

    @Override
    public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) {
        return false;
    }

    @Override
    public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) {
    Bitmap bitmap = textureView.getBitmap();

        // Initializing all color values
        int redmax = 0, greenmax = 0, bluemax = 0, redx = 0, bluex = 0, greenx = 0, redy = 0, bluey = 0, greeny = 0;

        int Pixel = bitmap.getHeight() * bitmap.getWidth();

        ByteBuffer Pixels = ByteBuffer.allocateDirect(4 * Pixel);

        for (int y = 0; y < bitmap.getHeight(); y++) { // Height
            for (int x = 0; x < bitmap.getWidth(); x++) {    // Width
                GLES20.glReadPixels(x, y, bitmap.getWidth(), bitmap.getHeight(), GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, Pixels);

                byte rValue = Pixels.get(0);
                byte gValue = Pixels.get(1);
                byte bValue = Pixels.get(2);
                byte A = Pixels.get(3);


                if (rValue > redmax) { // This is just to get max red Value in the frame
                    redmax = rValue;
                    redx = x;
                    redy = y;

                }
                if (bValue > bluemax) { // This is just to get max blue Value in the frame
                    bluemax = bValue;
                    bluex = x;
                    bluey = y;
                }

                if (gValue > greenmax) { // This is just to get max green Value in the frame
                    greenmax = gValue;
                    greenx = x;
                    greeny = y;
                }
            }
        }

        Log.i("Picture max red value", "R: " + redmax + " x: " + redx + " y: " + redy);
        Log.i("Picture max green value", "G: " + greenmax + " x: " + greenx + " y: " + greeny);
        Log.i("Picture max blue value", "B: " + bluemax + " x: " + bluex + " y: " + bluey);
        Log.i("Picture x and y value", "XY: " + " x: " + bitmap.getWidth() + " y: " + bitmap.getHeight());

        if ((redmax + bluemax + greenmax) > 760) {
            BitmapUtil.saveBitmap(bitmap, String.format("/sdcard/read_1" + UUID.randomUUID().toString() + ".jpg"));
        } else {
            bitmap.recycle();
        }

1 Ответ

0 голосов
/ 03 мая 2018

Так что, если я правильно понимаю, ваш код работает, но вам нужно его оптимизировать. Возможно, вы захотите дать полное описание того, что вы пытаетесь достичь, чтобы получить несколько идей, но из вашего кода может быть несколько указателей. Убедитесь, что вы сами создали тестовый сценарий с измеримыми результатами, чтобы увидеть, какая процедура оптимизировала ваш код и насколько.

Звонок на glReadPixels может занять очень много времени, поэтому постарайтесь максимально уменьшить его. Вы используете его в цикле for, который, если я правильно читаю, читает весь размер буфера, смещенный на x, y, что означает, что он переполнен рядом с другими вещами. Я считаю, что вы пытались сделать: GLES20.glReadPixels(x, y, 1, 1, который читает один пиксель в определенной позиции. Это должно дать вам прирост производительности, но, как упоминалось в комментарии @ Rabbid76, есть подозрение, что вы получите производительность, прочитав весь буфер, а затем перебирая пиксели.

Некоторые процедуры могут быть выгружены непосредственно в графический процессор, и проверка того, какой пиксель является «самым большим», выглядит прямо как одна из них. Вы можете создать FBO (объект кадрового буфера) и продолжать перерисовывать одну и ту же текстуру в буфер, который в два раза меньше размера каждого измерения, используя шейдеры для сохранения больших значений. В конце вы получите буфер с одним пикселем, который содержит ваше значение, но проблема в том, что вы потеряли позицию этого пикселя (где он был изначально).

Чтобы немного объяснить процедуру перерисовки текстуры, представьте, что у вас есть текстура 2x2, которая будет перерисована в буфер 1x1. Фрагментный шейдер выберет 4 ближайших пикселя и выведет самый большой, как в:

gl_fragColor = vec4(max(t1.r, max(t2.r, max(t3.r, t4.r))), max(t1.g, max(t2.r, max(t3.g, ...

, где tN - образцы в (0.25, 0.25), (0.75, 0.25), (0.25, 0.75), (0.75, 0.75).

Это будет выполняться только для одного фрагмента, но предыдущий вызов будет с тем же шейдером, перерисовывающим текстуру 4x4 в буфер 2x2, имеющий 4 фрагмента. То же самое 16x16 перерисовывается в 4x4 ... Так что все, что вам действительно нужно было сделать, - это преобразовать эти константы в шейдере в униформу и вычислить их.

Вы должны иметь возможность даже поместить эту работу в отдельный поток и пропускать кадры, если это разрешено и необходимо, когда это слишком дорого. Затем видео должно воспроизводиться без перерывов.

...