美文网首页
zxing、摄像机相关

zxing、摄像机相关

作者: 天下第九九八十一 | 来源:发表于2020-07-27 15:44 被阅读0次

看了下“自行”这个二维码扫码组件的demo,UI代码挺多的。

这速度太快了吧!

两个handler,一个处理摄像机,一个处于酱油线程中处理解码,。。。

干得好,我选择用一个 handler,不过那个酱油线程还是省不了,不然解码过程发生在主线程就不好了。


简要流程是:首先开启摄像机,调用startPreview,开始预览。

解码是通过在第一个handler中不断给摄像机设置setOneShotPreviewCallback(cb),在这个回调中拿到一帧图像的字节数组,传给解码Handler最后传给zxing-core。

解码的时候会将数据旋转一下,似乎没有必要,传送横着的数据,只要矩形范围设对了,zxing-core照样能识别出来。(不过也有可能zxing-core内部进行了旋转。)


原来摄像机的自动对焦是需要开发者手动调用并延时、连续调用autoFocus(cb)的。

于是,demo里面每次都新开一个 AsyncTask ,在 AsyncTask 里面调用 Thread.sleep(2000) 完成延时的效果。

干得好,我选择 postDelayed ……

方向传感器触发autoFocus:

https://www.cnblogs.com/wjw334/p/6744741.html?utm_source=itdadao&utm_medium=referral



于onResume中进行初始化,于onPause中销毁,这波难道都成了demo的标配了么(参考vlc官方demo)

干得好,我选择 onCreate 和 onDestory ……


与视频组件一样,camera除了可以用surfaceView预览,也可以选用textureView。后者暂停和恢复不会出现问题。

暂停久了,onResume的时候,摄像机会抛出 startPreview failedsetPreviewTexture failed等异常,此时,需要在 onResume 中重新初始化摄像机。

zxing-demo中还有许多没有用到的代码,比如闪光灯、曝光值,可以利用一下。



and:

处理画面拉伸。

扫码机,你得像个相机。不过这样一来,矩形范围要重新计算,倒是变得复杂了。

处理拉伸很简单,根据摄像机宽高分辨率、屏幕分辨率,计算textview.layoutparams的width、height。

和处理视频播放器的逻辑差不多,不多有一点是反着的,播放器一般是要把全部画面纳入(fit_center),摄像机最好还是屏幕上不留空白(center_crop)。

上面原版的修改版,下面别人的精简版(zxing-lite)

分屏模式,当宽度大于高度时,也算作 Configuration.ORIENTATION_LANDSCAPE的一种情况。所以横竖屏不能以 Configuration 中的数值为依据,而是要用到Display.getRotation

    public int getScreenOrientation() {
        int PORT=1,LAND=2;
        
        WindowManager windowService = (WindowManager)getSystemService(Context.WINDOW_SERVICE);
        
        int rotation = windowService.getDefaultDisplay().getRotation();
        
        if (Surface.ROTATION_0 == rotation) {
            rotation = PORT;
        } else if(Surface.ROTATION_180 == rotation) {
            rotation = PORT;
        } else if(Surface.ROTATION_90 == rotation) {
            rotation = LAND;
        } else if(Surface.ROTATION_270 == rotation) {
            rotation = LAND;
        }
        return rotation;
    }

来自 https://stackoverflow.com/questions/28041137/android-get-current-device-orientation

横屏、分屏时的处理




then:
可以让激光飞一会儿,飞出画面上的方框,此时,调大postInvalidateDelayed的间隔:

然后调低平时的间隔,使激光更流畅。

精简:

归并、精简,最终剩下九个相关类。

不过这也差不多了,区区一个二维码的界面效果,还不至于耗费太多时间。



ISBN码是有方向的。结果 zxing-lite 横着竖着都能扫,为啥?检测了多次而已。一次旋转数据,一次不旋转。

try 
                        rawResult = multiFormatReader.decodeWithState(bitmap);
                    } catch (ReaderException re) {// continue
                    } finally {
                        multiFormatReader.reset();
                    }

旋转数据,这就不可避免了,较慢。如果handler放在主线程,就会发现摄像机明显掉帧了。

可以通过只旋转、并传送扫码框内部的数据,达到减少计算量、节省内存的目的。

before:(旋转并传送整张图片)

https://github.com/yangxch/ScanZxing/blob/master/app/src/main/java/com/example/xch/scanzxing/zxing/decode/DecodeHandler.java搜索/***************竖屏更改3**********************/

byte[] rotatedData = new byte[data.length];   
         for (int y = 0; y < height; y++) {   
         for (int x = 0; x < width; x++)   
         rotatedData[x * height + height - y - 1] = data[x + y * width];   
         }   
         int tmp = width; // Here we are swapping, that's the difference to #11   
         width = height;   
         height = tmp;   
         data = rotatedData;  

after: (只处理框内内容)

if(rotate) {
            byte[] rotatedData = acquireTmpData(heightheight*widthwidth);
            for (int y = 0; y < heightheight; y++) {
                for (int x = 0; x < widthwidth; x++)
                    rotatedData[x + y * widthwidth] =  data[(y+left)  + (x+top) * sWidth];
            }
            data = rotatedData;
            return new PlanarYUVLuminanceSource(data, heightheight, widthwidth, 0, 0,  heightheight, widthwidth, false);
        }

数学关系还没搞明白,但灵感一闪就这么来了。上下文如下:
PlanarYUVLuminanceSource(源图像数据,原宽, 原高,竖屏模式,翻转一下图像再传给zxing-core)

public PlanarYUVLuminanceSource buildLuminanceSource(byte[] data, int sWidth, int sHeight, boolean rotated, boolean rotate) {
        Rect rect = getFramingRect();
        if (rect == null) {
            return null;
        }
        // Go ahead and assume it's YUV rather than die.
        //if(true) return new PlanarYUVLuminanceSource(data, sWidth, sHeight, 0, 0, sWidth, sHeight, false);
        //CMN.Log("buildLuminanceSource", width, height, rect.left, rect.top, rect.width(), rect.height());
        //CMN.Log("scale="+a.scale, "trans="+a.vTranslate);
        
        float scale = a.scale; // 源图像显示后的缩放比,比如0.5、0.9
        
        int left=(int)((rect.left-a.vTranslate.x)/scale);
        int top=(int)((rect.top-a.vTranslate.y)/scale);
        
        
        if(rotated) { //竖屏模式下,图像的数据其实还是横屏的样子。所以交换一下宽高。
            int tmp=sWidth;
            sWidth = sHeight;
            sHeight = tmp;
            tmp=left;
            left=top;
            top=tmp;
        }
        
        if(left<0) left=0;
        int widthwidth=(int)(rect.height()/scale);
        if(widthwidth+left>sWidth) {
            widthwidth=sWidth-left;
        }
        
        if(top<0) top=0;
        int heightheight=(int)(rect.height()/scale);
        
        if(heightheight+top>sHeight) {
            heightheight=sHeight-top;
        }
        
        if(rotate) {//必须旋转数据时,较为耗费CPU时间,故只处理必要的部分。
            byte[] rotatedData = acquireTmpData(heightheight*widthwidth);
            for (int y = 0; y < heightheight; y++) {
                for (int x = 0; x < widthwidth; x++)
                    rotatedData[x + y * widthwidth] =  data[(y+left)  + (x+top) * sWidth];
            }
            data = rotatedData;
            return new PlanarYUVLuminanceSource(data, heightheight, widthwidth, 0, 0,  heightheight, widthwidth, false);
        }
        

        return new PlanarYUVLuminanceSource(data, sWidth, sHeight, left, top,  widthwidth, heightheight, false);
    }

这里的旋转应该只是翻转,不知道有无翻转敏感的条码格式……

相关文章

网友评论

      本文标题:zxing、摄像机相关

      本文链接:https://www.haomeiwen.com/subject/ngpzlktx.html