Ниже приведен простой метод определения порогов для нахождения линий и их ширины, он должен работать достаточно надежно для любого количества строк. Приведенное ниже желто-черное изображение было обработано с использованием этого сценария, а черно-красное изображение иллюстрирует найденные линии с использованием параметров threshold = 0.3, min_line_width = 5
)
Сценарий усредняет строки изображения, а затем определяет базовые начальные и конечные позиции каждой строки на основе порога (который можно установить в диапазоне от 0 до 1) и минимальной ширины линии (в пикселях). Используя пороговое значение и минимальную ширину линии, вы можете легко фильтровать входные изображения, чтобы получить линии из них. Первая функция find_lines
возвращает все строки в изображении в виде списка кортежей, содержащих начало, конец, центр и ширину каждой строки. Вторая функция find_closest_band_width
вызывается с указанным x_position
и возвращает ширину ближайшей линии к этой позиции (при условии, что вы хотите расстояние до центра для каждой линии). Поскольку линии насыщены (255 отсечений на канал), их поперечные сечения не далеки от равномерного распределения, поэтому я не верю, что попытка подобрать какой-либо тип распределения действительно слишком сильно поможет, просто излишне усложнит .
import Image, ImageStat
def find_lines(image_file, threshold, min_line_width):
im = Image.open(image_file)
width, height = im.size
hist = []
lines = []
start = end = 0
for x in xrange(width):
column = im.crop((x, 0, x + 1, height))
stat = ImageStat.Stat(column)
## normalises by 2 * 255 as in your example the colour is yellow
## if your images start using white lines change this to 3 * 255
hist.append(sum(stat.sum) / (height * 2 * 255))
for index, value in enumerate(hist):
if value > threshold and end >= start:
start = index
if value < threshold and end < start:
if index - start < min_line_width:
start = 0
else:
end = index
center = start + (end - start) / 2.0
width = end - start
lines.append((start, end, center, width))
return lines
def find_closest_band_width(x_position, lines):
distances = [((value[2] - x_position) ** 2) for value in lines]
index = distances.index(min(distances))
return lines[index][3]
## set your threshold, and min_line_width for finding lines
lines = find_lines("8IxWA_sample.png", 0.7, 4)
## sets x_position to 59th pixel
print 'width of nearest line:', find_closest_band_width(59, lines)