python - 如何使用 Python(或 Perl)检测“暗”图像边框并裁剪到它?
问题描述
我有许多从视频中截取的小图像。下面是几个示例图像(存在各种类型的边缘):
简而言之,我正在尝试将图像裁剪到“主”图像的最近部分,该部分位于(几乎)均匀的“黑色”边框内......或者有时,有一点“抖动”边缘。你可以把它想象成去图像的中心,然后向外辐射,直到你碰到一个“矩形('黑色'或'接近黑色')边框'。
据我所知,最大的问题是确定图像周围“裁剪矩形”的位置和尺寸。但到目前为止,我还无法做到这一点。
我尝试在 ffmpeg 中使用“cropdetect”过滤器;Perl 没有什么真正有用的东西;...而且由于我是 Python 新手,我仍然没有弄清楚是否有任何简单的模块可以满足我的需求。我看过'scikit-image'......但完全被它迷惑了,因为我对Python没有足够的了解,更不用说图像格式,颜色深度,操作技术的足够“技术”知识,等让我使用'scikit-image'。
我将不胜感激有关如何解决此问题的任何建议,如果有一种简单的方法可以做到这一点,那就更好了。根据我对“scikit-image”的一点了解,似乎“Canny 边缘检测”或“prewitt_v”/“prewitt_h”过滤器可能是相关的......?
我正在使用 Python 3.7.0(和 Active State Perl v5.20.2,如果有任何使用方法),它们都在 Windows 8.1 下运行。
非常感谢您提出的任何建议。
解决方案
我已经尝试解决这个问题......但它不是很“强大”。当图像被灰度化时,它使用像素的亮度值:-
# ----
# this will find the 'black'-ish portions and crop the image to these points
# ozboomer, 25-Apr-2020 3-May-2020
#
# ---------
import pprint
import colorsys
from PIL import Image, ImageFilter
# ---- Define local functions (I *still* don't understand why I have to put these here)
def calculate_luminances(r, g, b):
"""Return luminance values of supplied RGB and greyscale of RGB"""
lum = (0.2126 * r) + (0.7152 * g) + (0.0722 * b) # luminance
H, S, V = colorsys.rgb_to_hsv(r, g, b) # HSV for the pixel RGB
R, G, B = colorsys.hsv_to_rgb(H, 0, V) # ...and greyscale RGB
glum = (0.2126 * R) + (0.7152 * G) + (0.0722 * B) # greyscale luminance
return(lum, glum)
# end calculate_luminances
def radial_edge(radial_vector, ok_range):
"""Return the point in the radial where the luminance marks an 'edge' """
print("radial_edge: test range=", ok_range)
edge_idx = -1
i = 0
for glum_value in radial_vector:
print(" radial_vector: i=", i, "glum_value=", "%.2f" % round(glum_value, 2))
if int(glum_value) in ok_range:
print(" IN RANGE! Return i=", i)
edge_idx = i
break
i = i + 1
# endfor
return(edge_idx)
# ---- End local function definitions
# ---- Define some constants, variables, etc
#image_file = "cap.bmp"
#image_file = "cap2.png"
#image_file = "cap3.png"
image_file = "Sample.jpg"
#image_file = "cap4.jpg"
output_file = "Cropped.png";
edge_threshold = range(0, 70) # luminance in this range = 'an edge'
#
# The image layout:-
#
# [0,0]----------+----------[W,0]
# | ^ |
# | | |
# | R3 |
# | | |
# +<--- R1 ---[C]--- R2 --->+
# | | |
# | R4 |
# | | |
# | v |
# [0,H]----------+----------[W,H]
#
# -------------------------------------
# Main Routine
#
# ---- Get the image file ready for processing
try:
im = Image.open(image_file) # RGB.. mode
except:
print("Unable to load image,", image_file)
exit(1)
# Dammit, Perl, etc code is SO much less verbose:-
# open($fh, "<", $filename) || die("\nERROR: Can't open file, '$filename'\n$!\n");
print("Image - Format, size, mode: ", im.format, im.size, im.mode)
W, H = im.size # The (width x height) of the image
XC = int(W / 2.0) # Approx. centre of image
YC = int(H / 2.0)
print("Image Centre: (XC,YC)=", XC, ",", YC)
# --- Define the ordinate ranges for each radial
R1_range = range(XC, -1, -1) # Actual range: XC->0 by -1 ... along YC ordinate
R2_range = range(XC, W, 1) # : XC->W by +1 ... along YC ordinate
R3_range = range(YC, -1, -1) # : YC->0 by -1 ... along XC ordinate
R4_range = range(YC, H, 1) # : YC->H by +1 ... along XC ordinate
# ---- Check each radial for its 'edge' point
radial_luminance = []
for radial_num in range (1,5): # We'll do the 4 midlines
radial_luminance.clear()
if radial_num == 1:
print("Radial: R1")
for x in R1_range:
R, G, B = im.getpixel((x, YC))
[lum, glum] = calculate_luminances(R, G, B)
print(" CoOrd=(", x, ",", YC, ") RGB=",
(R, G, B), "lum=", "%.2f" % round(lum, 2),
"glum=", "%.2f" % round(glum, 2))
radial_luminance.append(glum)
# end: get another radial pixel
left_margin = XC - radial_edge(radial_luminance, edge_threshold)
elif radial_num == 2:
print("Radial: R2")
for x in R2_range:
R, G, B = im.getpixel((x, YC))
[lum, glum] = calculate_luminances(R, G, B)
print(" CoOrd=(", x, ",", YC, ") RGB=",
(R, G, B), "lum=", "%.2f" % round(lum, 2),
"glum=", "%.2f" % round(glum, 2))
radial_luminance.append(glum)
# end: get another radial pixel
right_margin = XC + radial_edge(radial_luminance, edge_threshold)
elif radial_num == 3:
print("Radial: R3")
for y in R3_range:
R, G, B = im.getpixel((XC, y))
[lum, glum] = calculate_luminances(R, G, B)
print(" CoOrd=(", XC, ",", y, ") RGB=",
(R, G, B), "lum=", "%.2f" % round(lum, 2),
"glum=", "%.2f" % round(glum, 2))
radial_luminance.append(glum)
# end: get another radial pixel
top_margin = YC - radial_edge(radial_luminance, edge_threshold)
elif radial_num == 4:
print("Radial: R4")
for y in R4_range:
R, G, B = im.getpixel((XC, y))
[lum, glum] = calculate_luminances(R, G, B)
print(" CoOrd=(", XC, ",", y, ") RGB=",
(R, G, B), "lum=", "%.2f" % round(lum, 2),
"glum=", "%.2f" % round(glum, 2))
radial_luminance.append(glum)
# end: get another radial pixel
bottom_margin = YC + radial_edge(radial_luminance, edge_threshold)
# end: which radial we're processing
im.close()
crop_items = (left_margin, top_margin, right_margin, bottom_margin)
print("crop_items:", crop_items)
# ---- Crop the original image and save it
im = Image.open(image_file)
im2 = im.crop(crop_items)
im2.save(output_file, 'png')
exit(0)
# [eof]
我希望该radial_edge()
功能需要修改以检查周围像素以确定我们是否有真正的边缘......'因为ok_range
可能需要为每个图像确定电流,所以尝试自动化没有意义使用这样的脚本进行裁剪。
仍在寻找一种强大而可靠的方法来解决这个问题......
推荐阅读
- gerrit - Gerrit - 如何分叉存储库?
- python - 如何从 eventbrite 获取所有页面数据
- javascript - 如何知道数组的所有元素是否属于一个范围
- testing - 自动化支持多种编程语言的 API SDK 测试
- django - Django 选择字段。如何将初始值传递给表单
- python - Python - 预测手动值
- python - Django Custom User Admin field_sets 未显示在管理门户中
- python - 遍历列表和弹出数字
- google-sheets - Bigquery 的 Google 表格数据连接器消失了
- android - 我是否应该在不显示通知的情况下使用工作经理进行即时工作