Основы обработки изображений
Пару дней назад я столкнулся с проектом, в котором требовалось убирать белый фон у скетчей, когда они помещаются в определенную папку. Все это происходило в аппаратном сканере.
Вот пример скетча:
Первым шагом является установка зависимостей для этого проекта, которые перечислены ниже. Мы также будем использовать Python 3.7.
opencv_python==4.1.0.25 pip install opencv-python numpy==1.16.4 pip install numpy
После этого мы начнем с импорта всех необходимых модулей для проекта:
import cv2 import os import string import random from os import listdir from os.path import isfile, join, splitext import time import sys import numpy as np import argparse
Затем мы создаем три разные переменные: имя папки для просмотра, имя папки, в которой изображения будут находиться после обработки, и время опроса при просмотре папки (то есть, как часто он проверяет наличие изменений в папке - одна секунда в нашем случае)
watch_folder = ‘toprocess’ processed_folder = ‘processed’ poll_time = 1
Папки «toprocess» и «processing» пока будут находиться в одном каталоге нашего скрипта python.
Затем мы перейдем к нашей основной функции, которая будет следить за нашим каталогом «toprocess» и, если произойдут какие-либо изменения, обработает изображение, помещенное в эту папку.
before = dict([(f, None) for f in os.listdir(watch_folder)]) while 1: time.sleep(poll_time) after = dict([(f, None) for f in os.listdir(watch_folder)]) added = [f for f in after if not f in before] removed = [f for f in before if not f in after] if added: print(“Added “, “, “.join(added)) if added[0] is not None: processImage(added[0]) if removed: print(“Removed “, “, “.join(removed)) before = after
Этот код работает в бесконечном цикле, пока сценарий не будет убит. При запуске он сохраняет файлы в каталоге внутри словаря с именем «до». Далее шаги в бесконечном цикле разбиты ниже в псевдокоде:
- Сон в течение назначенного poll_time (1 секунда).
- Сохраните информацию о файле в каталоге в словаре с именем after.
- Сохраните то, что было добавлено, сравнив, что находится IN после и НЕ до (f для f после if не встречал раньше).
- Сохраните то, что было удалено, сравнив, что было В до и НЕ после.
- Проверьте последний добавленный элемент (добавлен [0]), если он есть, затем вызовите функцию, которую мы обсудим в части под названием processImage в файле.
- В случае удаления просто сообщите пользователю, распечатав некоторую информацию.
- Наконец, обновите до и после, чтобы получить последние файлы в каталоге.
Теперь о функции processImage
, которая является сердцем программы. Именно здесь происходит волшебство удаления фона OpenCV. Код поясняется комментариями ниже (требуются базовые знания OpenCV):
def processImage(fileName): # Load in the image using the typical imread function using our watch_folder path, and the fileName passed in, then set the final output image to our current image for now image = cv2.imread(watch_folder + ‘/’ + fileName) output = image # Set thresholds. Here, we are using the Hue, Saturation, Value color space model. We will be using these values to decide what values to show in the ranges using a minimum and maximum value. THESE VALUES CAN BE PLAYED AROUND FOR DIFFERENT COLORS hMin = 29 # Hue minimum sMin = 30 # Saturation minimum vMin = 0 # Value minimum (Also referred to as brightness) hMax = 179 # Hue maximum sMax = 255 # Saturation maximum vMax = 255 # Value maximum # Set the minimum and max HSV values to display in the output image using numpys' array function. We need the numpy array since OpenCVs' inRange function will use those. lower = np.array([hMin, sMin, vMin]) upper = np.array([hMax, sMax, vMax]) # Create HSV Image and threshold it into the proper range. hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV) # Converting color space from BGR to HSV mask = cv2.inRange(hsv, lower, upper) # Create a mask based on the lower and upper range, using the new HSV image # Create the output image, using the mask created above. This will perform the removal of all unneeded colors, but will keep a black background. output = cv2.bitwise_and(image, image, mask=mask) # Add an alpha channel, and update the output image variable *_, alpha = cv2.split(output) dst = cv2.merge((output, alpha)) output = dst # Resize the image to 512, 512 (This can be put into a variable for more flexibility), and update the output image variable. dim = (512, 512) output = cv2.resize(output, dim) # Generate a random file name using a mini helper function called randomString to write the image data to, and then save it in the processed_folder path, using the generated filename. file_name = randomString(5) + ‘.png’ cv2.imwrite(processed_folder + ‘/’ + file_name, output)
Это была довольно простая функция, и она выполняет свою работу правильно. Опять же, игра с порогами может дать еще лучшие результаты. И последнее, что нам нужно обсудить, - это вспомогательная мини-функция, которая генерирует случайную строку для имени файла.
def randomString(length): letters = string.ascii_lowercase return ‘’.join(random.choice(letters) for i in range(length))
Это простая функция. Он получает буквы, используя «строковую» библиотеку, а затем присоединяется к случайному выбору символов в зависимости от длины, которую вы передали. При передаче длины 5 будет сгенерирована строка из 5 символов.
Результат обработки показан ниже.
Конечно, этот результат можно улучшить, поэкспериментировав со значениями и получив более качественные отсканированные изображения.
Спасибо, что придерживались конца этой статьи. Надеюсь, это поможет вам в ваших будущих проектах.