You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Python提取相册页照片:白色背景下对比度优化方案

问题描述

我有一本实体相册,每页可能粘有一张或多张照片。我拍摄了每页的照片并放入同一文件夹,希望用Python批量提取其中的照片。现有OpenCV脚本会检测到过多轮廓(包含照片内部的轮廓),请问在页面背景为白色时,有什么合适的替代方法来调整对比度?

原脚本代码
# Read the image
img = cv2.imread("images/" + image)

# Convert the image to grayscale
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# Show gray image
cv2.imshow('Gray Image', gray)
cv2.waitKey(0)

blurred = cv2.GaussianBlur(gray, (5, 5), 0)

# Apply edge detection using the Canny edge detector
edged = cv2.Canny(blurred, 50, 150)

contours, _ = cv2.findContours(edged, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

min_area = 50000
filtered_contours = [cnt for cnt in contours if min_area < cv2.contourArea(cnt)]

extracted_photos = []
for i, contour in enumerate(filtered_contours):
    x, y, w, h = cv2.boundingRect(contour)
    extracted_photos.append(img[y:y+h, x:x+w])
    # Uncomment the following line to save individual photos
    # cv2.imwrite(f'photo_{i}.jpg', image[y:y+h, x:x+w])

# Show the extracted photos
cv2.imshow('Original Image', img)
cv2.waitKey(0)

for i, photo in enumerate(extracted_photos):
    cv2.imshow(f'Photo {i}', photo)
    cv2.waitKey(0)

cv2.destroyAllWindows()
效果展示

原始照片

原始照片

灰度照片

灰度照片

轮廓检测结果

轮廓检测结果

解决方案

针对白色背景的相册页面,可通过以下方法优化轮廓检测,避免提取到照片内部的轮廓:

1. 全局阈值分割(替代Canny边缘检测)

利用白色背景与照片区域的灰度差异,直接通过二值化分割出照片区域,这种方法不会检测到照片内部的细节边缘:

import cv2
import numpy as np

# 读取图像
img = cv2.imread("images/" + image)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# 高斯模糊降噪
blurred = cv2.GaussianBlur(gray, (5, 5), 0)

# 反转二值化:将白色背景转为黑色,照片区域转为白色
_, thresh = cv2.threshold(blurred, 220, 255, cv2.THRESH_BINARY_INV)

# 仅提取最外层轮廓
contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

# 过滤小面积轮廓(根据实际照片大小调整阈值)
min_area = 50000
filtered_contours = [cnt for cnt in contours if cv2.contourArea(cnt) > min_area]

# 提取并保存照片
extracted_photos = []
for i, cnt in enumerate(filtered_contours):
    x, y, w, h = cv2.boundingRect(cnt)
    extracted_photos.append(img[y:y+h, x:x+w])
    # cv2.imwrite(f'extracted_photo_{i}.jpg', img[y:y+h, x:x+w])

# 查看结果
cv2.imshow('Threshold Image', thresh)
cv2.waitKey(0)
for i, photo in enumerate(extracted_photos):
    cv2.imshow(f'Extracted Photo {i}', photo)
    cv2.waitKey(0)
cv2.destroyAllWindows()

2. 自适应阈值分割(应对光照不均)

如果拍摄时光照不均匀,部分背景偏暗,用自适应阈值能根据局部区域灰度调整分割标准,提升准确性:

# 替换全局阈值部分的代码
thresh = cv2.adaptiveThreshold(blurred, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 11, 2)

3. 对比度增强(缩小背景与照片的灰度差距)

若照片与背景灰度差异不明显,先增强对比度再分割:

# 使用CLAHE限制对比度自适应直方图均衡化,避免局部过曝
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8))
equalized = clahe.apply(gray)

# 后续步骤同全局阈值分割
blurred = cv2.GaussianBlur(equalized, (5,5), 0)
_, thresh = cv2.threshold(blurred, 220, 255, cv2.THRESH_BINARY_INV)

4. 形态学操作(去除噪点轮廓)

阈值分割后若存在小噪点轮廓,用形态学操作消除:

# 创建5x5的结构元素
kernel = np.ones((5,5), np.uint8)
# 闭操作填充照片内部的小孔洞,开操作去除背景噪点
thresh = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel)
# thresh = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel)

内容的提问来源于stack exchange,提问作者Mart

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 23:22:09