Из 5000 фотографий номерных знаков я хочу определить, какой дублирующийся код у этих номеров.
Вот 2 примера дублирования кода на номерном знаке.
В первом примере повторяющийся код равен 2, а во втором примере повторяющийся код равен 1.
С пакетом Magick и Tesseract, см. код ниже, я смог получить часть фотографии из первого примера, где есть повторяющийся код, и прочитать повторяющийся код. Только во втором примере и на других фото фото другое.
Поэтому я ищу что-то, что может распознать дублирующийся код и прочитать дублирующийся код. Примечание. Дублирующийся код — всегда выше, первый отступ.
У кого-нибудь есть идея, как автоматически прочитать повторяющийся код с 5000 разных фотографий?
library(magick)
library(tesseract)
#Load foto:
foto <- image_read("C:/Users/camie/OneDrive/Documenten/kenteken3.jpg")
#Get piece of photo where duplicate code is retrieved:
foto2 <- image_crop(foto,"10X24-620-170")
#read duplicate code:
cat(ocr(foto3))
Что с существованием нескольких макетов для голландских номерных знаков, я не уверен, что вы можете просто жестко закодировать метод для извлечения значения дублирования. Также вы не указываете, всегда ли каждое изображение, которое у вас есть, имеет одинаковое качество и/или ориентацию/масштаб/перекос/и т. д.
Теоретически вы можете применить Сверточная нейронная сеть, который классифицирует номерные знаки по нескольким категориям. (0 для n/a, 1 для 1, 2 для 2 и т. д.) Однако я не знаком с родственными пакетами в R, поэтому не могу указать вам на некоторые из них.
Я думаю, что CNN - хороший вариант, может быть, я могу использовать для него тензорный поток. Но риск с CNN на всей фотографии заключается в том, что нейронная сеть будет пытаться найти закономерность в цифрах и буквах. Хотя, если вам нужно только применить cnn или ocr к дублирующемуся коду, я думаю, что это будет хорошая модель раньше.
Вот подход, основанный на пакете EBImage
. ImageMagik отлично подходит для обработки изображений, но я думаю, что EBImage
может предоставить больше количественных инструментов, которые здесь будут полезны. Как и во всей обработке изображений, большое значение имеет качество входного изображения. Предлагаемый здесь подход, скорее всего, выиграет от удаления шума и артефактов, масштабирования и, возможно, кадрирования.
Кроме того, некоторые лицензии содержат дополнительные символы в интересующей позиции, которые не являются числами. Очевидно, что для таких случаев требуется дополнительная предварительная обработка и фильтрация.
# Starting from EBImage
if (!require(EBImage)) {
source("http://bioconductor.org/biocLite.R")
biocLite("EBImage")
library(EBImage)
}
# Test images
# setwd(<image directory>)
f1 <- "license1.jpg"
f2 <- "license2.jpg"
# Read image and convert to normalized greyscale
img0 <- readImage(f1)
img <- channel(img0, "grey")
img <- normalize(img)
# plot(img) # insert plot or display commands as desired
# Rudimentary image process for ~300 pixel wide JPEG
xmf <- medianFilter(img, 1)
xgb <- gblur(xmf, 1)
xth <- xgb < otsu(xgb) # Otsu's algorithm to determine best threshold
xto <- opening(xth, makeBrush(3, shape = "diamond"))
Двоичное (пороговое) изображение было создано и очищено для идентификации объектов, как показано здесь.
# Create object mask with unique integer for each object
xm <- bwlabel(xto)
# plot(colorLabels(xm)) # optional code to visualize the objects
В дополнение к элементарному процессу обработки изображения может применяться некоторая «обработка объектов», как показано здесь. Объекты по краям не представляют интереса, поэтому они удаляются. Точно так же можно удалить артефакты, вызывающие появление горизонтальных (широких) полос.
# Drop objects touching the edge
nx <- dim(xm)[1]
ny <- dim(xm)[2]
sel <- unique(c(xm[1,], xm[nx,], xm[,1], xm[,ny]))
sel <- sel[sel != 0]
xm <- rmObjects(xm, sel, reenumerate = TRUE)
# Drop exceptionally wide objects (33% of image width)
major <- computeFeatures.moment(xm)[,"m.majoraxis"]
sel <- which(major > nx/3)
xm <- rmObjects(xm, sel, reenumerate = TRUE)
Следующая логика идентифицирует центр масс каждого объекта с функцией computeFeatures.moment
от EBImage
. Кажется, что основные символы будут располагаться вдоль горизонтальной линии, а объект-кандидат будет выше этой линии (нижнее значение y в объекте EBImage
Image). Альтернативным подходом может быть поиск объектов, наложенных друг на друга, т. е. объектов с похожими значениями x.
В примерах, которые я исследовал, одного стандартного отклонения от медианного значения y для центра масс оказалось достаточно для идентификации объекта-кандидата. Это используется для определения пределов, показанных ниже. Конечно, эта логика должна быть скорректирована в соответствии с реальными данными.
# Determine center of mass for remaining objects
M <- computeFeatures.moment(xm)
x <- M[,1]
y <- M[,2]
# Show suggested limit on image (y coordinates are inverted)
plot(img)
limit <- median(y) - sd(y)
abline(h = limit, col = "red")
# Show centers of mass on original image
ok <- y < limit
points(x[!ok], y[!ok], pch = 16, col = "blue")
points(x[ok], y[ok], pch = 16, col = "red")
На изображении показаны сегментированные объекты после отбрасывания объектов вдоль края. Красным цветом показаны кандидаты, синим — некандидаты.
Поскольку некоторые лицензии имеют два символа над дефисом, следующий код выбирает самого левого из возможных кандидатов, расширяет маску объекта и возвращает прямоугольную обрезку изображения, которую можно передать ocr()
.
# Accept leftmost (first) of candidate objects
left <- min(x[which(ok)])
sel <- which(x == left)
# Enlarge object mask and extract the candidate image
xm <- dilate(xm, makeBrush(7, "disc"))
ix <- range(apply(xm, 2, function(v) which(v == sel)))
iy <- range(apply(xm, 1, function(v) which(v == sel)))
xx <- ix[1]:ix[2]
yy <- iy[1]:iy[2]
# "Return" selected portion of image
ans <- img[xx, yy] # this is what can be passed to tesseract
plot(ans, interpolate = FALSE)
Вот немасштабированное и извлеченное изображение-кандидат из примера 1:
Тот же код, примененный к этому примеру, дает следующее:
Еще несколько проверок на наличие ошибок и нелогичных условий, и код можно было собрать в единую функцию и применить к списку из 5000 файлов! Но, конечно, это предполагает, что они правильно отформатированы и т. д. и т. д.
Спасибо за ответ Дэвид О! Звучит действительно хорошо! Я собираюсь пройти через ваше объяснение еще больше в ближайшие дни, но я обязательно попробую.
Удачи! Я с нетерпением жду возможности увидеть, как это работает для вас. Кстати, я исправил скрытую ошибку в своем коде! 1
было изменено на sel
. Обязательно используйте обновленную версию.
Привет, Дэвид, я был в отпуске, поэтому мне потребовалось немного времени, прежде чем попробовать. Но код хорошо работает на некоторых картинках. Но при большом количестве снимков качество картинки плохое. На некоторых картинках bwlabel не мог хорошо различать объекты, а на некоторых картинках h text mining (cat (ocr)) плохо читал рисунок.
Спасибо, что сообщили мне, как это работает. С реальными изображениями обработка изображения перед выделением признаков, вероятно, является наиболее важным шагом. В моем примере шаг, помеченный как «зачаточный процесс изображения», следует заменить более подходящим кодом для ваших изображений. (R может работать, но может быть не лучшим для этого ...) Это должно быть адаптировано к вашим изображениям, но фильтр Собеля для улучшения краев и / или нерезкая маска для локального повышения контраста могут быть хороши для JPEGS. Удачи.
Спасибо за ответ CZorio! Извините за недостающую информацию. В данном исследовании мы ориентируемся только на легковые автомобили. Эти 5000 изображений имеют почти такое же расположение, как и в примере.