这篇博客将介绍如何使用Python,OpenCV和Scikit-Image检测低对比度图像。
在良好受控的光照条件下拍摄照片,将更便于处理。
在动态条件下拍摄的照片将更具有个别性,使得不能覆盖所有的场景及边缘案例。
检测低对比度的一个应用是:在应用算法前,过滤掉低对比度的图像,因其往往会导致不够准确的结果。
1. 效果图
非低对比度图像效果图,可以看到最大轮廓正确检测且展示。右侧的边缘图也很清晰,前景与背景较好的区分开。
低对比度图像效果图,可以看到轮廓检测的结果map图,边界框模糊,前景与背景的分界处并没有正确展示。因此在检测时会直接跳过绘制最大边缘:
2. 原理
-
低对比度图像/帧会产生什么问题?怎样才能检测到它们?
低对比度图像在光线亮区域和暗区域之间具有很小的差异,使得难以看到对象的边界与背景的分界处。
越是在光照良好的条件下拍照的图像,越是便于编码处理。边缘案例的复杂通道图像难以覆盖全,且不易处理。
低对比度图像会使硬编码算法(例如,模糊尺寸,阈值限制,Canny Edge检测参数等)可能导致不正确/无法使用的输出。因此,在图像处理中,可以检测并丢弃掉低对比度的图像,以保证算法能得出正确的结果。
3. 源码
# USAGE
# python detect_low_contrast_image.py --input images
# 导入必要的包
from skimage.exposure import is_low_contrast # 该函数用于通过检查图像的直方图然后确定亮度范围跨越全范围的分数量来检测低对比度图像。
from imutils.paths import list_images
import argparse
import imutils
import cv2
# 构建命令行参数及解析
# --input 输入图像路径
# --thresh 低对比度的阈值,0.35意味着当亮度区域少于整个图像的0.35时,认为时低对比度图像;由于OpenCV中的图像是由一系列值的无符号8位整数表示[0,255]。
# 如果像素强度的分布占据该[0,255]范围的35%,则图像被认为是低对比度。
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--input", required=True,
help="path to input directory of images")
ap.add_argument("-t", "--thresh", type=float, default=0.45,
help="threshold for low contrast")
args = vars(ap.parse_args())
# 获取输入图像路径
imagePaths = sorted(list(list_images(args["input"])))
# 遍历图像路径
for (i, imagePath) in enumerate(imagePaths):
# 从磁盘加载,保持宽高比的缩放图像,转换为灰度图
print("[INFO] processing image {}/{}".format(i + 1, len(imagePaths)))
image = cv2.imread(imagePath)
image = imutils.resize(image, width=450)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# 高斯平滑图像以减少高频噪音,并执行边缘检测
blurred = cv2.GaussianBlur(gray, (5, 5), 0)
edged = cv2.Canny(blurred, 30, 150)
# 初始化非低对比度的文本及颜色,绿色
text = "Low contrast: No"
color = (0, 255, 0)
# 检查图像是否低对比度
if is_low_contrast(gray, fraction_threshold=args["thresh"]):
# 更新低对比度文件及颜色,红色
text = "Low contrast: Yes"
color = (0, 0, 255)
# 如果不是低对比度,继续处理
else:
# 在边缘图中找到最大的轮廓,认为其实彩色校正图片的外轮廓
cnts = cv2.findContours(edged.copy(), cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)
cnts = imutils.grab_contours(cnts)
c = max(cnts, key=cv2.contourArea)
# 在图像上绘制最大轮廓
cv2.drawContours(image, [c], -1, (0, 255, 0), 2)
# for i,c in enumerate(cnts):
# # 在图像上绘制最大轮廓
# cv2.drawContours(image, [c], -1, (0, 255, 0), 2)
# 输出图像上绘制文本
cv2.putText(image, text, (5, 25), cv2.FONT_HERSHEY_SIMPLEX, 0.8,
color, 2)
# 展示输出图像和边缘图
cv2.imshow("Image", image)
cv2.imshow("Edge", edged)
cv2.waitKey(0)