使用 OpenCV 在 Android 中实现夜视摄像头
在 Android 中使用 OpenCV 实现夜视。
引言
软件夜视通常通过直方图均衡化或伽马校正来实现,而这两种方法都已在 OpenCV 中得到支持。对于任何 Android 设备,我们可以使用 OpenCV4Android 来处理设备捕获的图像。
背景
这段代码是在我开发 myMobKit 时编写的。你可以在 这里 找到源代码。
使用代码
在 Android 编程中,在相机预览期间,你将获得一个字节数组,它是一个 YUV420sp 图像。
使用 OpenCV,将图像转换为灰度图像,并使用 OpenCV API 对图像应用直方图均衡化。
@Override
public byte[] process(final byte[] source) {
try {
if (source == null) return null;
if (sourceFrame == null) {
if (!isColor) {
this.sourceFrame = new Mat(height + (height / 2), width, CvType.CV_8UC1);
this.processedFrame = new Mat(height + (height / 2), width, CvType.CV_8UC1);
} else {
this.sourceFrame = new Mat(height + (height / 2), width, CvType.CV_8UC1);
this.processedFrame = new Mat(height + (height / 2), width, CvType.CV_8UC3);
this.ycrcb = new Mat();
}
}
sourceFrame.put(0, 0, source);
// convert sourceFrame to gray scale
if (!isColor) {
Imgproc.cvtColor(sourceFrame, processedFrame, Imgproc.COLOR_YUV420p2GRAY);
// Apply Histogram Equalization
Imgproc.equalizeHist(processedFrame, processedFrame);
// Convert to JPEG
return CvUtils.grayToJpeg(processedFrame, imageQuality);
} else {
// Histogram equalization using YCrCb
Imgproc.cvtColor(sourceFrame, ycrcb, Imgproc.COLOR_YUV2RGBA_NV21, 4);
Imgproc.cvtColor(ycrcb, ycrcb, Imgproc.COLOR_RGB2YCrCb);
Core.split(ycrcb, channels);
Imgproc.equalizeHist(channels.get(0), channels.get(0));
Core.merge(channels, processedFrame);
Imgproc.cvtColor(processedFrame, processedFrame, Imgproc.COLOR_YCrCb2BGR);
return CvUtils.toJpegByteArray(processedFrame, imageQuality);
}
} catch (Exception e) {
LOGE(TAG, "[process] Unable to process byte[]", e);
return null;
}
}
结果
对于伽马校正,
private void configureLut() {
releaseMat(lutMat);
lutMat = new Mat(1, 256, CvType.CV_8UC1);
double invGamma = 1.0 / gamma;
int size = (int) (lutMat.total() * lutMat.channels());
byte[] temp = new byte[size];
lutMat.get(0, 0, temp);
for (int j = 0; j < 256; ++j) {
temp[j] = (byte) (Math.pow((double) j / 255.0, invGamma) * 255.0);
}
lutMat.put(0, 0, temp);
}
@Override
public byte[] process(final byte[] source) {
try {
if (source == null) return null;
if (sourceFrame == null) {
sourceFrame = new Mat(height + (height / 2), width, CvType.CV_8UC1);
processedFrame = new Mat(height + (height / 2), width, CvType.CV_8UC1);
}
sourceFrame.put(0, 0, source);
// Gamma correction
if (isColor) {
Imgproc.cvtColor(sourceFrame, processedFrame, Imgproc.COLOR_YUV2BGRA_NV21);
Core.LUT(processedFrame, lutMat, processedFrame);
// Convert to JPEG
return CvUtils.toJpegByteArray(processedFrame, imageQuality);
} else {
Imgproc.cvtColor(sourceFrame, processedFrame, Imgproc.COLOR_YUV420p2GRAY);
Core.LUT(processedFrame, lutMat, processedFrame);
// Convert to JPEG
return CvUtils.grayToJpeg(processedFrame, imageQuality);
}
} catch (Exception e) {
LOGE(TAG, "[process] Unable to process byte[]", e);
return null;
}
}
要查看完整的源代码,请查看 GitHub 仓库。
历史
2016-10-01 - 初始发布。