Как определить «темную» границу изображения и обрезать ее, используя Python (или Perl)? - PullRequest
0 голосов
/ 13 марта 2020

У меня есть несколько маленьких изображений, которые являются снимками экрана из видео. Пример изображения может быть собран в http://www.filedropper.com/test-image.

enter image description here

Короче, я пытаюсь обрезать изображение до ближайшая часть «основного» изображения, которая находится внутри (почти) равномерно «черной» границы. Вы можете думать об этом, как о переходе к центру изображения, а затем излучать его до тех пор, пока не достигнете «прямоугольной angular (« черной ») границы».

Самая большая проблема, насколько я вижу, это чтобы определить местоположение и размеры «обрезающего прямоугольника» вокруг изображения ... но до сих пор я не смог ничего с этим сделать.

Я пытался использовать фильтры 'cropdetect' в FFmpeg; в Perl нет ничего действительно полезного; ... и поскольку я новичок в Python, я все еще не определился, есть ли какой-нибудь простой модуль, который может делать то, что мне нужно. Я посмотрел на 'scikit-image' ... но он был совершенно сбит с толку, поскольку у меня недостаточно хороших знаний о Python, не говоря уже о достаточно "технических" знаниях об изображении форматы, глубина цвета, методы манипуляции и т. д. c, которые позволили бы мне использовать 'scikit-image'.

Буду признателен за любые предложения о том, как решить эту проблему, даже лучше, если бы существовал простой способ сделать это. Из моего небольшого понимания 'scikit-image' кажется, что фильтры 'Canny edge Detect' или 'prewitt_v' / 'prewitt_h' могут быть уместны ...?

Я использую Python 3.7.0 (и Active State Perl v5.20.2, если есть возможность использовать это), оба работают под Windows 8.1.

Большое спасибо за любые предложения.

1 Ответ

0 голосов
/ 03 мая 2020

Я попытался решить эту проблему ... но это не очень "надежно". Он использует значения яркости пикселей, когда изображение было серого цвета: -

# ----
#  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, вероятно, должен быть определен для каждого изображения, поэтому нет смысла пытаться автоматизировать кадрирование, используя такой скрипт.

Все еще ищите надежный и надежный способ решения этой проблемы ...

...