Creo que debe ser un problema muy simple, pero no puedo encontrar una solución o una palabra clave eficaz para la búsqueda.

Sólo tengo esta imagen.

Cosecha de los bordes negros con OpenCV

Los bordes negros son inútiles, así que quiero cortar, dejando sólo el ícono de Windows (y el fondo azul).

No quiero calcular las coordenadas y el tamaño de los iconos de Windows. GIMP y Photoshop tiene una especie de autorecorte función. OpenCV no tiene uno?

InformationsquelleAutor Gqqnbig | 2012-11-24

6 Comentarios

  1. 45

    No estoy seguro si todas las imágenes son como este. Pero para esta imagen, a continuación es una simple python-opencv código para recortar.

    primera bibliotecas de importación :

    import cv2
    import numpy as np
    

    Leer la imagen, convertir a escala de grises, y hacer que en la imagen binaria por valor de umbral de 1.

    img = cv2.imread('sofwin.png')
    gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
    _,thresh = cv2.threshold(gray,1,255,cv2.THRESH_BINARY)
    

    Ahora encontrar contornos en ella. Habrá un solo objeto, por lo que encontrar rectángulo delimitador para él.

    contours,hierarchy = cv2.findContours(thresh,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
    cnt = contours[0]
    x,y,w,h = cv2.boundingRect(cnt)
    

    Ahora recortar la imagen, y guardar en otro archivo.

    crop = img[y:y+h,x:x+w]
    cv2.imwrite('sofwinres.png',crop)
    

    A continuación es el resultado :

    Cosecha de los bordes negros con OpenCV

    • Gracias. Te refieres a OpenCV no proporcionar un establecimiento de la función para cortar los bordes.
    • +1 Bonita respuesta. Y sí, @LoveRight, que es exactamente lo que significa. Otro enfoque para lidiar con este problema se discutido aquí.
    • Sólo quiero señalar que usted puede jugar con el umbral un poco si no hace lo que quiere, he tenido que subir el 1 a alrededor de 10. _,thresh = cv2.threshold(gray,10,255,cv2.THRESH_BINARY)
    • Puede usted por favor ayuda con el equivalente de c++?
    • Muchas gracias, señor. A mí me funcionó con sólo un borde negro en la parte inferior. Para OpenCV 3, habrá un ligero cambio en el código:contours,hierarchy,_ = cv2.findContours(thresh,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE) 🙂
    • para ser honesto numpy es mucho mejor como imagen de la librería de opencv, pero un poco más difícil de entender de qué hacer para conseguir el efecto deseado
    • _, contornos, _ = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE) (Pequeños Cambios)

  2. 9
    import numpy as np
    
    def autocrop(image, threshold=0):
        """Crops any edges below or equal to threshold
    
        Crops blank image to 1x1.
    
        Returns cropped image.
    
        """
        if len(image.shape) == 3:
            flatImage = np.max(image, 2)
        else:
            flatImage = image
        assert len(flatImage.shape) == 2
    
        rows = np.where(np.max(flatImage, 0) > threshold)[0]
        if rows.size:
            cols = np.where(np.max(flatImage, 1) > threshold)[0]
            image = image[cols[0]: cols[-1] + 1, rows[0]: rows[-1] + 1]
        else:
            image = image[:1, :1]
    
        return image
    
    • ¿por qué eliminar el canal de color? flatImage = np.max(image, 2)
    • Debido a la utilización de un umbral de gris de valor. Hay varias implementaciones pertinentes, como de costumbre, este es sólo uno de ellos.
  3. 4

    ACEPTAR, por lo que la integridad, la he implementado cada una de las recomendaciones anteriores, se añadió una versión iterativa del algoritmo recursivo (una vez corregido) y realizó un conjunto de pruebas de rendimiento.

    TLDR: Recursiva es probablemente el mejor para el caso promedio (pero uso la de abajo–el OP tiene un par de fallos), y el autorecorte es la mejor para las imágenes que esperar a estar casi vacío.

    Conclusiones generales:
    1. El algoritmo recursivo de arriba tiene un par de off-by-1 errores en él. Versión corregida está por debajo.
    2. El cv2.findContours función tiene problemas con la falta de imágenes rectangulares, y de hecho incluso algunos adornos de la imagen en varios escenarios. He añadido una versión que utiliza cv2.CHAIN_APPROX_NONE a ver si te ayuda (que no ayuda).
    3. El autorecorte aplicación es excelente para las imágenes, pero pobre para denso, la inversa de la recursivo/algoritmo iterativo.

    import numpy as np
    import cv2
    
    def trim_recursive(frame):
      if frame.shape[0] == 0:
        return np.zeros((0,0,3))
    
      # crop top
      if not np.sum(frame[0]):
        return trim_recursive(frame[1:])
      # crop bottom
      elif not np.sum(frame[-1]):
        return trim_recursive(frame[:-1])
      # crop left
      elif not np.sum(frame[:, 0]):
        return trim_recursive(frame[:, 1:])
        # crop right
      elif not np.sum(frame[:, -1]):
        return trim_recursive(frame[:, :-1])
      return frame
    
    def trim_contours(frame):
      gray = cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY)
      _,thresh = cv2.threshold(gray,1,255,cv2.THRESH_BINARY)
      _, contours, hierarchy = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
      if len(contours) == 0:
        return np.zeros((0,0,3))
      cnt = contours[0]
      x, y, w, h = cv2.boundingRect(cnt)
      crop = frame[y:y + h, x:x + w]
      return crop
    
    def trim_contours_exact(frame):
      gray = cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY)
      _,thresh = cv2.threshold(gray,1,255,cv2.THRESH_BINARY)
      _, contours, hierarchy = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
      if len(contours) == 0:
        return np.zeros((0,0,3))
      cnt = contours[0]
      x, y, w, h = cv2.boundingRect(cnt)
      crop = frame[y:y + h, x:x + w]
      return crop
    
    def trim_iterative(frame):
      for start_y in range(1, frame.shape[0]):
        if np.sum(frame[:start_y]) > 0:
          start_y -= 1
          break
      if start_y == frame.shape[0]:
        if len(frame.shape) == 2:
          return np.zeros((0,0))
        else:
          return np.zeros((0,0,0))
      for trim_bottom in range(1, frame.shape[0]):
        if np.sum(frame[-trim_bottom:]) > 0:
          break
    
      for start_x in range(1, frame.shape[1]):
        if np.sum(frame[:, :start_x]) > 0:
          start_x -= 1
          break
      for trim_right in range(1, frame.shape[1]):
        if np.sum(frame[:, -trim_right:]) > 0:
          break
    
      end_y = frame.shape[0] - trim_bottom + 1
      end_x = frame.shape[1] - trim_right + 1
    
      # print('iterative cropping x:{}, w:{}, y:{}, h:{}'.format(start_x, end_x - start_x, start_y, end_y - start_y))
      return frame[start_y:end_y, start_x:end_x]
    
    def autocrop(image, threshold=0):
      """Crops any edges below or equal to threshold
    
      Crops blank image to 1x1.
    
      Returns cropped image.
    
      """
      if len(image.shape) == 3:
        flatImage = np.max(image, 2)
      else:
        flatImage = image
      assert len(flatImage.shape) == 2
    
      rows = np.where(np.max(flatImage, 0) > threshold)[0]
      if rows.size:
        cols = np.where(np.max(flatImage, 1) > threshold)[0]
        image = image[cols[0]: cols[-1] + 1, rows[0]: rows[-1] + 1]
      else:
        image = image[:1, :1]
    
      return image
    

    A continuación, prueba en la que he hecho esta sencilla función:

    import datetime
    import numpy as np
    import random
    
    ITERATIONS = 10000
    
    def test_image(img):
      orig_shape = img.shape
      print ('original shape: {}'.format(orig_shape))
      start_time = datetime.datetime.now()
      for i in range(ITERATIONS):
        recursive_img = trim_recursive(img)
      print ('recursive shape: {}, took {} seconds'.format(recursive_img.shape, (datetime.datetime.now()-start_time).total_seconds()))
      start_time = datetime.datetime.now()
      for i in range(ITERATIONS):
        contour_img = trim_contours(img)
      print ('contour shape: {}, took {} seconds'.format(contour_img.shape, (datetime.datetime.now()-start_time).total_seconds()))
      start_time = datetime.datetime.now()
      for i in range(ITERATIONS):
        exact_contour_img = trim_contours(img)
      print ('exact contour shape: {}, took {} seconds'.format(exact_contour_img.shape, (datetime.datetime.now()-start_time).total_seconds()))
      start_time = datetime.datetime.now()
      for i in range(ITERATIONS):
        iterative_img = trim_iterative(img)
      print ('iterative shape: {}, took {} seconds'.format(iterative_img.shape, (datetime.datetime.now()-start_time).total_seconds()))
      start_time = datetime.datetime.now()
      for i in range(ITERATIONS):
        auto_img = autocrop(img)
      print ('autocrop shape: {}, took {} seconds'.format(auto_img.shape, (datetime.datetime.now()-start_time).total_seconds()))
    
    
    def main():
      orig_shape = (10,10,3)
    
      print('Empty image--should be 0x0x3')
      zero_img = np.zeros(orig_shape, dtype='uint8')
      test_image(zero_img)
    
      print('Small image--should be 1x1x3')
      small_img = np.zeros(orig_shape, dtype='uint8')
      small_img[3,3] = 1
      test_image(small_img)
    
      print('Medium image--should be 3x7x3')
      med_img = np.zeros(orig_shape, dtype='uint8')
      med_img[5:8, 2:9] = 1
      test_image(med_img)
    
      print('Random image--should be full image: 100x100')
      lg_img = np.zeros((100,100,3), dtype='uint8')
      for y in range (100):
        for x in range(100):
          lg_img[y,x, 0] = random.randint(0,255)
          lg_img[y, x, 1] = random.randint(0, 255)
          lg_img[y, x, 2] = random.randint(0, 255)
      test_image(lg_img)
    
    main()
    

    …Y LOS RESULTADOS…

    Empty image--should be 0x0x3
    original shape: (10, 10, 3)
    recursive shape: (0, 0, 3), took 0.295851 seconds
    contour shape: (0, 0, 3), took 0.048656 seconds
    exact contour shape: (0, 0, 3), took 0.046273 seconds
    iterative shape: (0, 0, 3), took 1.742498 seconds
    autocrop shape: (1, 1, 3), took 0.093347 seconds
    Small image--should be 1x1x3
    original shape: (10, 10, 3)
    recursive shape: (1, 1, 3), took 1.342977 seconds
    contour shape: (0, 0, 3), took 0.048919 seconds
    exact contour shape: (0, 0, 3), took 0.04683 seconds
    iterative shape: (1, 1, 3), took 1.084258 seconds
    autocrop shape: (1, 1, 3), took 0.140886 seconds
    Medium image--should be 3x7x3
    original shape: (10, 10, 3)
    recursive shape: (3, 7, 3), took 0.610821 seconds
    contour shape: (0, 0, 3), took 0.047263 seconds
    exact contour shape: (0, 0, 3), took 0.046342 seconds
    iterative shape: (3, 7, 3), took 0.696778 seconds
    autocrop shape: (3, 7, 3), took 0.14493 seconds
    Random image--should be full image: 100x100
    original shape: (100, 100, 3)
    recursive shape: (100, 100, 3), took 0.131619 seconds
    contour shape: (98, 98, 3), took 0.285515 seconds
    exact contour shape: (98, 98, 3), took 0.288365 seconds
    iterative shape: (100, 100, 3), took 0.251708 seconds
    autocrop shape: (100, 100, 3), took 1.280476 seconds
    
  4. 1

    Cómo sobre una mancha pequeña función recursiva?

    import cv2
    import numpy as np
    def trim(frame):
        #crop top
        if not np.sum(frame[0]):
            return trim(frame[1:])
        #crop bottom
        elif not np.sum(frame[-1]):
            return trim(frame[:-2])
        #crop left
        elif not np.sum(frame[:,0]):
            return trim(frame[:,1:]) 
        #crop right
        elif not np.sum(frame[:,-1]):
            return trim(frame[:,:-2])    
        return frame
    

    De carga y el umbral de la imagen para garantizar que las áreas oscuras son de color negro:

    img = cv2.imread("path_to_image.png")   
    thold = (img>120)*img
    

    A continuación, llamar a la función recursiva

    trimmedImage = trim(thold)
    
  5. 0

    En caso de que ayuda a nadie, me fui con este tweak de @wordsforthewise del reemplazo para un PIL-solución basada en:

    bw = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    rows, cols = bw.shape
    
    non_empty_columns = np.where(bw.max(axis=0) > 0)[0]
    non_empty_rows = np.where(bw.max(axis=1) > 0)[0]
    cropBox = (min(non_empty_rows) * (1 - padding),
                min(max(non_empty_rows) * (1 + padding), rows),
                min(non_empty_columns) * (1 - padding),
                min(max(non_empty_columns) * (1 + padding), cols))
    
    return img[cropBox[0]:cropBox[1]+1, cropBox[2]:cropBox[3]+1 , :]
    

    (Es un tweak en que el código original se espera recortar un fondo blanco en lugar de negro.)

  6. 0

    De La Versión De Python 3.6


    Recortar las imágenes y se insertan en un ‘CropedImages’ carpeta

    import cv2
    import os
    
    arr = os.listdir('./OriginalImages')
    
    for itr in arr:
        img = cv2.imread(itr)
        gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
        _,thresh = cv2.threshold(gray, 120, 255, cv2.THRESH_BINARY)
        _, contours, _ = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
        cnt = contours[0]
        x,y,w,h = cv2.boundingRect(cnt)
        crop = img[y:y+h,x:x+w]
        cv2.imwrite('CropedImages/'+itr,crop)
    

    Cambiar el número de 120 a otros en la línea 9 y tratar de imágenes, Se trabajará

Dejar respuesta

Please enter your comment!
Please enter your name here