Camera电路、图像传感器问题汇总

常见电路

  • VCC表示给芯片电源供电;

  • VDD表示给芯片中的器件单独供电,当然也可也从内部电源的VCC整合过来,就不用外部单独提供;所以有些芯片只有VCC,没有VDD,所以一般VDD<=VCC

  • AVDD表示模拟电压,给芯片中的模拟器件供电,比如camera供电就要用到AVDD,也是相对于DVDD区别出来的,

  • DVDD表示数字电压,给芯片的数字信号供电,比如0101,

  • AFVDD表示auto focus VDD自动对焦电压,是针对一些马达之类的电压,

  • DOVDD和IOVDD是芯片引脚出来的电压,

  • PVDD是功率电源。

  • AVCC是模拟电源。

  • CVDD是内核电压。

图像传感器问题

出现横向条纹

  • 出现横向的紫色或者绿色条纹,一般情况下是时序有问题。
    在这里插入图片描述

  • 现象:闪现的紫色或绿色干扰线

  • 原因:Hsync和高速线距离太近太长,产生了耦合(10cm的高速线产生约5pF左右的耦合电容),导致Hsync不能迅速拉升至90%的区域,相位不同步,最终数据采集有错位。然后因为YUV算法的作用,引起绿线和紫色的闪现。

  • 解决方法:绝对禁止将Hsync、pclk、mclk这三根线挤在一起走线。
    Hsync夹在低速线SDA和SCL之间
    PCLK和MCLK如果一定要贴着走线,最好拉开一点距离,当中夹一根地线。

颜色和亮度不连续

  • 一般是数据线存在短路、断路和连错的问题。图像会出现类似于水波纹的等高线或大面积色偏,D信号丢失画面整体也会色偏,比如RGB565,D0~D4均断路图像会因蓝色和绿色信号丢失过多而呈红色

  • 一根数据线虚焊导致的等高线及颜色失真的例子在这里插入图片描述

两根数线和其他设备复用导致的偏绿问题

  • 8根数据线中有两根被其它设备复用了,所以这两根没出数据。
    在这里插入图片描述

数据线接反的情况在这里插入图片描述

数据线错位

  • OV2640初始化,但是预览图像不对,通过ps发现,只有G通道有信号,RB通道全黑
    在这里插入图片描述

  • 2640的10根数据线与CSI的16根数据线的连接关系,硬件工程师布板时弄错了将sensor的10根数据线D[0]D[9]连接到了CSI的D[4]D[15],而CSI取得的是D[8]~D[15]的8bit数据,结果造成了数据位的错位与丢失,造成了以上图像的情况。

数据线图例图汇总

  • 第一张是亮度很低的情况下抓到的原始数据图像
    在这里插入图片描述

  • 第二张是将光圈调大以后出现的现象
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

图像中只有红或绿颜色

  • Y和U/V的顺序不对。将摄像头的采样格式由CbYCrY改为YCbYCr后,颜色就对了
    在这里插入图片描述

  • 横向无规则条纹

  • 竖向无规则条纹

  • 偏红

热噪声.

  • 过一段时间噪点逐渐增多

. 在这里插入图片描述

  • 开始工作时正常的,,没有色点,工作过一段时间后,模组开始出现色点,而且色点越来越多. 如上图所示. 原因:

  • 工作一段时间sensor温度会提升,温度升高会加剧半导体材料的本征激发。这会导致sensor
    S/N降低,noise加剧。此状况与sensor材料关系较大,后端或软件处理可以减缓此状况但不能根除。这种叫hot pixel,是芯片过热造成的。

模拟电压过低或不稳定

  • 模拟电压过低导致很强的光才能感应图像,并且偏色。

  • 例1如下图所示,只有天花板上的灯管才感应成像,其他部分很模糊。

在这里插入图片描述

  • 模拟电压过低导致竖向条纹。提高AVDD后问题解决。
    在这里插入图片描述

  • 在调试 OV7725时发现,刚打开摄像头时图像有条纹,开了一段时间后图像就正常了,不正常的图像如下。查出问题了,是模拟电压不稳导致的。
    在这里插入图片描述

背部材料太薄导致“鬼影”

  • 补强的表面要用亚光黑油,防止漏光。

  • OV2715异常图像,感测到了背面电路板的漏光,图像如下:

在这里插入图片描述

  • GC0307 图像异常,如下图。 中间有条线,像分层那样的线,正常情况是没有。格科微的叫我们四周都补胶,就解决啦
    在这里插入图片描述
    由噪声导致的图像横纹

  • 在新版的电路板中,将CMOS移到离主IC较远的地方现象就消失了,之前是放在主IC的背面,猜测是主IC对CMOS造成的影响,比如在模拟电压上引入噪声。
    示例1 如下图所示。
    在这里插入图片描述

  • cmos为ov的30w像素,型号为ov7141。使用时出项很明显的水平方向的横波纹。
    采用3.3v和2.5v供电,其中VDD_C和VDD_A是由2.5v供电,pcb上直接将他们连在一起接2.5v。直接铺地,没有划分模拟地和数字地。
    在这里插入图片描述

  • 使用外接电源对AVDD供电,没有出现上述现象。可以确定是由主板的电源噪声引起的 。改板后效果还可以,主要改动有:

  • 原来是两层板,现在用的是4层板,有专门的电源层

  • LDO输出改用大容量的钽电容滤波。示波器测量电源纹波 比以前小了。

工频干扰

  • 在室外自然光下如果不会出现,那一定是50/60Hz引起的flicker;

Lens校准参数未调好导致的中间较亮的情况

  • 用OV9650摄像头模组拍的图片,像素是800 X 600;中间较亮

在这里插入图片描述

  • 从硬件来说,可能是lens set与sensor不匹配,特别是CRA,你得看看datasheet两者是否差距太大。

  • 软件上,可能是lens
    correction没调好(个人感觉楼主状况属此列),设定好correction区域然后将gain值拉高让中心与周边亮度差异减少,如果此时整个画面过曝,可以将整体gain值再往下调(也可以设定曝光参数来减少画面亮度)。

  • 按以上方法调整OV9650的几个与lens correction有关的寄存器的值,使中心和四周的亮度均匀!

通过自动增益控制降低噪点

  • 在调试OV7675时,图像有左边是模糊的,右边正常,图片如下:

在这里插入图片描述

  • 将 AGC 调小之后不会出现了,但是没之前亮了.效果如下:
    在这里插入图片描述

自动曝光计算出现的偏绿现象

  • OV7670:

  • 在室外光线较亮拍摄时,画面颜色任何时候都正常。

  • 在室内光线较暗拍摄时,刚打开摄像时拍摄的画面偏绿,几秒钟之后就会恢复正常。
    属于正常现象。

在这里插入图片描述

  • OV7670 30W 计算AE时间比较长。在计算AE的过程中容易出现偏色现象。 可以丢帧或者延时解决这个问题

时序不对导致的图像上部或下部出现条纹 因Vsync偏移出现问题的例子如下图所示。

  • 因Vsync偏移出现问题如下图所示:

在这里插入图片描述

  • camera 模组的timing调整不了。修改AP的camera控制,使垂直同步偏移12 rows. 图像输出正确。

lens镜间反射导致的眩光

  • 这是一颗5M的模组拍摄的图片,天花板的灯在视场外边缘,图中为何出现紫红色的光?是什么原因造成的?

在这里插入图片描述

  • 属眩光现象,一般是由于多片lens镜间反射造成。通过改善镀膜制程,增加镜片透射率可以缓解次问题。

  • 另外,这张照片光心偏到左边去了,holder偏移?lens set circle够大啊,这种偏移都能cover掉。

  • 此现象是lens组装到模组上面的机构问题产生。

pclk与vsync布线干扰

  • 在调试一款手机摄像头(OV7675)时,发现画面垂直不同步,主要是画面的下半部分跳动很厉害,上半部分是好的.

  • 帧同步VSYNC和PCLK布线有干扰

PCLK采样边沿选择不对导致的噪点

  • 图中有噪点

在这里插入图片描述

  • 转换了一下Pclk的极性,这个躁点的问题得到了很好的解决。

  • ov7675拍出来的照片发绿。可能是PCLK采样边缘不对,可以试试将pclk反向。也可能是数据线缺失问题。

  • 如下图所示。通过修改pclk的上升沿和下降沿就解决了。在这里插入图片描述

主要有两点:

  • 修改PCLK的上升沿的斜率。 2.或者修改I/O的上升沿的斜率。

  • 原因是不同厂家的模组layout的走线的长短,FPC的厚薄,都可能影响到PCLK的获取,
    FPC的公差过大,或者头板的制作是否有什么问题,都可能引起这个问题。 如果可以通过硬件的方式改变PCLK上升沿的斜率,也可以解决这个问题。

  • 通过修改pclk的上升沿和下降沿就解决了

FPN问题

  • 白天或亮一点的地方是没有这个问题,就只有在低照度下使用闪光灯拍照会有这样的情形。

  • FPN( fixed pattern noise), 无解。

在这里插入图片描述

台阶效应

  • gain过大,把digitalize的量化步距,乘大了,就出现台阶效应。还与内部的量化精度不够,有关系。

  • 若不同的颜色通道的gain不同(白平衡计算出的R/G/B_gain不同),会出现color phase error。

  • 示意图,如下,只画了B、G两个通道,B_gain比G_gain大,会造成灰阶的景物,有的地方B大,有的地方G大,就会出现颜色不断交替。

在这里插入图片描述

  • 结合上台阶效应,可能就会表现成的这幅图

因电源问题产生的竖向条纹

  • 已经确定是电源的问题了,我在每个电源都 并上了一个大电容 ,条纹消失了。用CPU的I/O采集的,效果很好。
    在这里插入图片描述

Lens与摄像头不匹配导致的部分偏红现象

  • 图中下方居中的地方偏红。ov工程师将LENS
    CORRECTION调到了极限问题还存在,确认是LENS与SENSOR不匹配造成的,模组厂家更换了镜头后问题基本解决。

在这里插入图片描述

根据图片发现:

  • 首先你的照片awb就不对,本身这张照片就没有达到白平衡

  • 照片边界锯齿现象很严重.

  • 色偏问题,你首先要了解一下你的sensor的Lenschief ray
    angle角度是多少,还有lens的CRA是多少.如果lens的CRA小于sensor的.一定会有偏色的现象.要么换lens.如果市场上找不合适
    的Lens,就说明sensor 本身品质不是很好

  • 理论上lens shading是解决lens的通透率不一样的问题.但也许各家回加自己的算法,可以一试.

  • 如果Lens 和sensor都已经固定,可以人为想一些办法来减少色差

  • 可以将颜色调淡点,这样就不太明显

  • 做AWB校正,排除不同sensor对RGB感应的不同,引起AWB曲线走的不准.

  • CRA通俗的讲是lens的主轴光线和对成像有贡献的最大的如射光线的夹角,一般Lens厂商会提供CRA曲线,因为Lens从中心到四周的CRA是不一样的.

  • 偏红除了SHADING外可能还是要调AWB,因为图片的下方其实就是一片白色,sensor在照白色的地方出现了偏红,再试试调整一下AWB,或者在灯箱里看看R,G,B的三条线是
    否重合!

  • 如果是AWB的问题,那为什么图像还有白色区域呢?AWB是不会调的有的偏色,有的不偏

  • 如果是CRA不比配,那出现的偏色应该是对称的,下面偏紅则上面一定会偏紅。
    个人觉得应该是漏光造成的,不是barrel就是通光孔那里引入了杂光。

DOVDD28走线过细过长以及地线不合理 现象:花屏

  • 2.8V电压因为导线上的电阻吸收了电压,导致驱动能力不够。地线被拉高并产生毛刺现象,影响信号完整性和数据采集。

在这里插入图片描述

DVDD电压有问题

  • 图中的高光部分是办公室窗户。其它部分全黑,没有任何细节? 是什么原因?AWB?AGC?还是对比度啊?
    在这里插入图片描述

  • 问题解决了,是DVDD电压不对。

  • datasheet写的1.8V,问了FAE结果是1.2V。

增益小导致的白色条纹问题

  • 当对着白色的物体时,刚进入预览时,会出现下图中显示的条纹,当移动手机时,则这种条纹消失,以后也不会出现,只有再次进入预览时可能会出现,
    在这里插入图片描述

  • 加大了初始化代码中的增益之后,就可以了。

帧率问题导致的图像错位

  • Sensor为0v9655 在拍sxga 130万图像有时会出现图像错位的问题(如图),vga的则不会出现
    在这里插入图片描述

  • 帧率太高了,曝光时间短了.可以调整VBLANK,HBLANK来解决 再降低FPS到5

电源噪声

  • OV9653出现如图所示的横向纹路。

  • 电源问题,AVDD加钽电容就好了。估计是电源纹波比较严重导致的。

  • 13
    点赞
  • 123
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
以下是使用camera2扫描二维码并且扫描结束后打开闪光灯的代码: ```java private CameraManager mCameraManager; private String mCameraId; private CameraDevice mCameraDevice; private CameraCaptureSession mCaptureSession; private CaptureRequest.Builder mPreviewRequestBuilder; private TextureView mTextureView; private HandlerThread mBackgroundThread; private Handler mBackgroundHandler; private ImageReader mImageReader; private boolean mFlashSupported; private boolean mFlashState; private final CameraDevice.StateCallback mCameraCallback = new CameraDevice.StateCallback() { @Override public void onOpened(@NonNull CameraDevice cameraDevice) { mCameraDevice = cameraDevice; createCameraPreviewSession(); } @Override public void onDisconnected(@NonNull CameraDevice cameraDevice) { cameraDevice.close(); mCameraDevice = null; } @Override public void onError(@NonNull CameraDevice cameraDevice, int error) { cameraDevice.close(); mCameraDevice = null; } }; private final CameraCaptureSession.StateCallback mSessionCallback = new CameraCaptureSession.StateCallback() { @Override public void onConfigured(@NonNull CameraCaptureSession cameraCaptureSession) { if (mCameraDevice == null) { return; } mCaptureSession = cameraCaptureSession; try { mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE); setAutoFlash(mPreviewRequestBuilder); mCaptureSession.setRepeatingRequest(mPreviewRequestBuilder.build(), null, mBackgroundHandler); } catch (CameraAccessException e) { e.printStackTrace(); } } @Override public void onConfigureFailed(@NonNull CameraCaptureSession cameraCaptureSession) { Toast.makeText(getApplicationContext(), "Failed", Toast.LENGTH_SHORT).show(); } }; private final ImageReader.OnImageAvailableListener mOnImageAvailableListener = new ImageReader.OnImageAvailableListener() { @Override public void onImageAvailable(ImageReader reader) { mBackgroundHandler.post(new ImageSaver(reader.acquireLatestImage())); } }; private static class ImageSaver implements Runnable { private final Image mImage; ImageSaver(Image image) { mImage = image; } @Override public void run() { // 解析二维码 mImage.close(); } } @Override protected void onResume() { super.onResume(); startBackgroundThread(); if (mTextureView.isAvailable()) { openCamera(mTextureView.getWidth(), mTextureView.getHeight()); } else { mTextureView.setSurfaceTextureListener(mSurfaceTextureListener); } } @Override protected void onPause() { closeCamera(); stopBackgroundThread(); super.onPause(); } private void startBackgroundThread() { mBackgroundThread = new HandlerThread("CameraBackground"); mBackgroundThread.start(); mBackgroundHandler = new Handler(mBackgroundThread.getLooper()); } private void stopBackgroundThread() { mBackgroundThread.quitSafely(); try { mBackgroundThread.join(); mBackgroundThread = null; mBackgroundHandler = null; } catch (InterruptedException e) { e.printStackTrace(); } } private void openCamera(int width, int height) { setUpCameraOutputs(width, height); configureTransform(width, height); mCameraManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE); try { if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) { return; } mCameraManager.openCamera(mCameraId, mCameraCallback, null); } catch (CameraAccessException e) { e.printStackTrace(); } } private void closeCamera() { try { mCaptureSession.stopRepeating(); mCaptureSession.abortCaptures(); } catch (CameraAccessException e) { e.printStackTrace(); } mCaptureSession.close(); mCaptureSession = null; mCameraDevice.close(); mCameraDevice = null; mImageReader.close(); mImageReader = null; } private void createCameraPreviewSession() { try { SurfaceTexture texture = mTextureView.getSurfaceTexture(); texture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight()); Surface surface = new Surface(texture); mPreviewRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); mPreviewRequestBuilder.addTarget(surface); mImageReader = ImageReader.newInstance(mPreviewSize.getWidth(), mPreviewSize.getHeight(), ImageFormat.YUV_420_888, 2); mImageReader.setOnImageAvailableListener(mOnImageAvailableListener, mBackgroundHandler); mPreviewRequestBuilder.addTarget(mImageReader.getSurface()); mCameraDevice.createCaptureSession(Arrays.asList(surface, mImageReader.getSurface()), mSessionCallback, mBackgroundHandler); } catch (CameraAccessException e) { e.printStackTrace(); } } private void setUpCameraOutputs(int width, int height) { mCameraManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE); try { for (String cameraId : mCameraManager.getCameraIdList()) { CameraCharacteristics characteristics = mCameraManager.getCameraCharacteristics(cameraId); Integer facing = characteristics.get(CameraCharacteristics.LENS_FACING); if (facing != null && facing == CameraCharacteristics.LENS_FACING_BACK) { StreamConfigurationMap map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); if (map == null) { continue; } Size largest = Collections.max(Arrays.asList(map.getOutputSizes(ImageFormat.YUV_420_888)), new CompareSizesByArea()); mImageReader = ImageReader.newInstance(largest.getWidth(), largest.getHeight(), ImageFormat.YUV_420_888, 2); mPreviewSize = chooseOptimalSize(map.getOutputSizes(SurfaceTexture.class), width, height, largest); mCameraId = cameraId; break; } } } catch (CameraAccessException e) { e.printStackTrace(); } } private void configureTransform(int viewWidth, int viewHeight) { if (null == mTextureView || null == mPreviewSize) { return; } int rotation = getWindowManager().getDefaultDisplay().getRotation(); Matrix matrix = new Matrix(); RectF viewRect = new RectF(0, 0, viewWidth, viewHeight); RectF bufferRect = new RectF(0, 0, mPreviewSize.getHeight(), mPreviewSize.getWidth()); float centerX = viewRect.centerX(); float centerY = viewRect.centerY(); if (Surface.ROTATION_90 == rotation || Surface.ROTATION_270 == rotation) { bufferRect.offset(centerX - bufferRect.centerX(), centerY - bufferRect.centerY()); matrix.setRectToRect(viewRect, bufferRect, Matrix.ScaleToFit.FILL); float scale = Math.max((float) viewHeight / mPreviewSize.getHeight(), (float) viewWidth / mPreviewSize.getWidth()); matrix.postScale(scale, scale, centerX, centerY); matrix.postRotate(90 * (rotation - 2), centerX, centerY); } mTextureView.setTransform(matrix); } private static Size chooseOptimalSize(Size[] choices, int width, int height, Size aspectRatio) { List<Size> bigEnough = new ArrayList<>(); for (Size option : choices) { if (option.getHeight() == option.getWidth() * aspectRatio.getHeight() / aspectRatio.getWidth() && option.getWidth() >= width && option.getHeight() >= height) { bigEnough.add(option); } } if (bigEnough.size() > 0) { return Collections.min(bigEnough, new CompareSizesByArea()); } else { return choices[0]; } } private static class CompareSizesByArea implements Comparator<Size> { @Override public int compare(Size lhs, Size rhs) { return Long.signum((long) lhs.getWidth() * lhs.getHeight() - (long) rhs.getWidth() * rhs.getHeight()); } } private final TextureView.SurfaceTextureListener mSurfaceTextureListener = new TextureView.SurfaceTextureListener() { @Override public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int width, int height) { openCamera(width, height); } @Override public void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture, int width, int height) { configureTransform(width, height); } @Override public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) { return true; } @Override public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) { } }; private void setAutoFlash(CaptureRequest.Builder requestBuilder) { if (mFlashSupported) { if (mFlashState) { requestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH); } else { requestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON); } } } private void setFlashState(boolean state) { mFlashState = state; if (mCaptureSession != null) { try { mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, mFlashState ? CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH : CaptureRequest.CONTROL_AE_MODE_ON); mCaptureSession.setRepeatingRequest(mPreviewRequestBuilder.build(), null, mBackgroundHandler); } catch (CameraAccessException e) { e.printStackTrace(); } } } ``` 在 `createCameraPreviewSession()` 方法中可以看到,我们添加了一个 `ImageReader` 用于获取相机捕获的数据,我们可以在 `mOnImageAvailableListener` 监听器中对数据进行解析,这里我们可以使用 `Zxing` 库进行解析二维码: ```java private static class ImageSaver implements Runnable { private final Image mImage; ImageSaver(Image image) { mImage = image; } @Override public void run() { ByteBuffer buffer = mImage.getPlanes()[0].getBuffer(); byte[] data = new byte[buffer.remaining()]; buffer.get(data); PlanarYUVLuminanceSource source = new PlanarYUVLuminanceSource(data, mImage.getWidth(), mImage.getHeight(), 0, 0, mImage.getWidth(), mImage.getHeight(), false); BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source)); MultiFormatReader reader = new MultiFormatReader(); try { Result result = reader.decode(bitmap); Log.d(TAG, "result: " + result.getText()); } catch (NotFoundException e) { e.printStackTrace(); } finally { mImage.close(); } } } ``` 至于如何打开闪光灯,我们可以在 `setAutoFlash()` 方法中设置 `CaptureRequest.CONTROL_AE_MODE` 参数为 `CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH` 或 `CaptureRequest.CONTROL_AE_MODE_ON` 来控制闪光灯的开关状态。同时,在 `setFlashState()` 方法中可以动态地切换闪光灯状态。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值