|
|
|||||
Могу предложить упрощенный способ проверки совпадения изображений по гистограмме. Поскольку слово WATERMARK написано черным цветом, то на гистограмме оно будет находиться в крайнем левом углу шириной максимум 10 яркости от абсолютно черной + вносить небольшие изменения в крайний правый край гистограммы, так как буквы залиты белым цветом.
Что делаем - берем два изображения, находим гистограммы по их битмапам через .histogram(); получаем два вектора гистограмм. отрезаем немного от правой части от этих векторов (часть информации о буквах в крайней правой части, часть в крайней левой) Поскольку у букв белая заливка, то левый край вектора тоже будет затронут,его тоже нужно обрезать. Сравниваем две гистограммы. Центры гистограмм должны быть полностью идентичны Останется только подобрать края отрезания правой и левой частей гистограммы, чтобы убирать всю информацию о черных буквах с белой заливкой |
|
|||||
Регистрация: Jan 2009
Сообщений: 1,651
|
Ребят, я просто не могу удержаться от вставки этой картинки, в ответ на пост Дипа. Прошу меня простить.
Цитата:
Цитата:
Цитата:
Короче, Дип. На самом деле алгоритмы распознования изображений или проекты типа http://www.tineye.com/ именно так и устроенны. Но ты не представляешь себе, сколько там мелких "но" и сколько вещей необходимо учесть при программировании таких алгоритмов. Так что, если картинки абсолютно одинаковые и отличаются только наличием ватермарка, то эту задачу лучше решить другим способом.
__________________
мой пустой блог |
|
|||||
Пиу пиу, а у меня все работает =Р
Суть -пост №11 package { import flash.display.BitmapData; import flash.display.Sprite; import flash.events.Event; import flash.display.Loader; import flash.net.URLRequest; import flash.display.LoaderInfo; import flash.display.Bitmap; import flash.filters.ColorMatrixFilter; import flash.geom.Point; /** * ... * @author Cyrill Nadezhdin */ public class Main extends Sprite { private var firstImage:BitmapData; private var secondImage:BitmapData; private var firstImageGrey:Vector.<Vector.<Number>>; private var secondImageGrey:Vector.<Vector.<Number>>; private var firstLoaded:Boolean = false; private var secondLoaded:Boolean = false; private var firstImagePath:String = "photo_1.jpg"; private var secondImagePath:String = "photo_1_wm.jpg"; //Верхняя граница обрезки гистограммы private var whiteThreshold:int = 0; //Нижняя граница обрезки гистограммы private var blackThreshold:int = 0; //Два массива, требуемые для применения черно-белого фильтра к картинке private var grayScale:Array = [0.3086, 0.3086, 0.3086, 0, 0, 0.3086, 0.3086, 0.3086, 0, 0, 0.3086, 0.3086, 0.3086, 0, 0, 0, 0, 0, 1, 0]; private var filter:ColorMatrixFilter = new ColorMatrixFilter(grayScale); //Эпсилон, максимальное отклонение двух гистограмм, при котором считаем картинки одинаковыми private var epsilon:Number = 1000; //Просто загрузка файлов в лоб, не обращайте внимания public function Main():void { var loader1:Loader = new Loader(); loader1.contentLoaderInfo.addEventListener(Event.COMPLETE, onFirstComplete); loader1.load(new URLRequest(firstImagePath)); var loader2:Loader = new Loader(); loader2.contentLoaderInfo.addEventListener(Event.COMPLETE, onSecondComplete); loader2.load(new URLRequest(secondImagePath)); } private function onFirstComplete(e:Event):void { firstImage = Bitmap(LoaderInfo(e.target).content).bitmapData; //================================================================= //Делаем из картинки черно-белую, нас не интересуют цвета firstImage.applyFilter(firstImage, firstImage.rect, new Point(), filter); firstImageGrey = firstImage.histogram(); //================================================================= firstLoaded = true; if (secondLoaded) { compare(); } } private function onSecondComplete(e:Event):void { secondImage = Bitmap(LoaderInfo(e.target).content).bitmapData; //================================================================= //Делаем из картинки черно-белую, нас не интересуют цвета secondImage.applyFilter(secondImage, secondImage.rect, new Point(), filter); secondImageGrey = secondImage.histogram(); //================================================================= secondLoaded = true; if (firstLoaded) { compare(); } } private function compare():void { var splicedFirstHisto:Vector.<Number> = firstImageGrey[0]; var splicedSecondHisto:Vector.<Number> = secondImageGrey[0]; //Обрезаем гистограммы снизу. с яркости 0 до значения порога для черного цвета splicedFirstHisto.splice(0, blackThreshold); splicedSecondHisto.splice(0, blackThreshold); //Обрезаем гистограммы сверху. Последние n значений, определяемые порогом белого цвета splicedFirstHisto.splice(256 - whiteThreshold, 256 - whiteThreshold); splicedSecondHisto.splice(256 - whiteThreshold, 256 - whiteThreshold); //Находим разницу, сравнивая две гистограммы if (findDistinction(splicedFirstHisto, splicedSecondHisto) < epsilon) { trace("ЭТО ТЕ САМЫЕ КАРТИНКИ УРУРУ"); } else { trace("Разные совсем"); } } private function findDistinction(vectorA:Vector.<Number>, vectorB:Vector.<Number>):Number { var dist:Number = 0; for (var i:uint = 0; i < vectorA.length; i++) { dist += Math.sqrt(Math.abs(vectorA[i] - vectorB[i])); } trace(dist); return dist; } } } Можно настраивать точность с помощью изменения переменных whiteThreshold, blackThreshold и epsilon Как оказалось, без обрезки гистограммы можно вполне обойтись Проверил на четырех фотках - определяет правильно все) Если же все таки обрезать - то сумма значений whiteThreshold и blackThreshold не должна превышать 255, я не делал проверку. (у нас 255 уровней яркости) ============================= Небольшая поправочка - попробовал поменять размер картинок с 500х500 до 150х150, оказывается не учел количество пикселей при сравнении картинок. Надо переделать функцию сравнения, чтобы считала проценты пикселей с заданной яркостью, а не само количество пикселей private function findDistinction(vectorA:Vector.<Number>, vectorB:Vector.<Number>):Number { var dist:Number = 0; var firstSum:Number = 0; var secondSum:Number = 0; for (var i:uint = 0; i < vectorA.length;i++ ) { firstSum += vectorA[i]; } for (i = 0; i < vectorB.length;i++) { secondSum += vectorB[i]; } trace(firstSum); trace(secondSum); for (i = 0; i < vectorA.length; i++) { dist += Math.sqrt(Math.abs(vectorA[i]/firstSum - vectorB[i]/secondSum)); } trace(dist); return dist; } Теперь можно сравнивать даже изображения с разным размером, у меня во всех случаях при epsilon = 2 правильно определило Последний раз редактировалось KumoKairo; 01.03.2013 в 22:54. |
|
|||||
буду краток
модератор форума
Регистрация: Sep 2003
Адрес: Ближайшее Замкадье
Сообщений: 3,110
Записей в блоге: 28
|
О, класс, про therehold я и не подумал. Хотя особо не думал.
Вообще я про свою задачу для arp: https://bitbucket.org/k0t0vich/arp Цитата:
__________________
Отряд Котовскага |
|
|||||
Регистрация: Feb 2013
Сообщений: 176
|
Почему нет предложений про нейросеть? Удобная же задача)))
|
|
|||||
Modus ponens
|
Сравнение такого плана (опознание картинок не точно похожих друг на друга) - это задача из области самообучающихся програм... Но, естесственно, если можно как-то схитрить, то имеет смысл (т.е. если картинки, за исключением группы пикселов идентичны, а не просто похожи.
Что да имело бы смысл сделать: изначально сравнивать не все картинки со всеми картинками, а вычислить хеш от каждой картинки, и сравнивать хеши (если создать хеши длиной 32 бита, то сравнения будут очень быстрыми). Можно воспользоваться CRC для этого, или тот же MD5 - главное быстрый алгоритм и короткий хеш. Для исключения вероятности потерять совпадающие картинки (которая будет очень незначительной в ситуации с хешированием, но все же будет, если где-то водяной знак не так приклеился, или во время приклеивания другие части картинки как-то исказились) можно сделать блум фильтр, для груп пикселов и сравнивать блум фильтры от картинок. Т.е. разделить картинки на непрерывные блоки, и сложить все пикселы блока в один блум фильтр. Такие блоки будет гораздо быстрее сравнить. Еще варианты: для предварительной фильтрации использовать вычисление гистограмы, или усредненного цвета всей картинки. Добавлено через 2 минуты Нейронные сети сами по себе очень непростой вопрос. Если уж что-то самому организовывать, то support vector machine было бы проще реализовать... но простота тут относительная С другой стороны есть проект fann который уже реализовывает эти сети, но биндингов к нему в AS3 я что-то не припомню
__________________
Hell is the possibility of sanity |
|
|||||
буду краток
модератор форума
Регистрация: Sep 2003
Адрес: Ближайшее Замкадье
Сообщений: 3,110
Записей в блоге: 28
|
Олег какой такой md5? Картинки не на 100% идентичны.
__________________
Отряд Котовскага |
|
|||||
Modus ponens
|
Я же прямым текстом и написал:
Цитата:
__________________
Hell is the possibility of sanity |
Часовой пояс GMT +4, время: 01:08. |
|
« Предыдущая тема | Следующая тема » |
Теги |
распознавание изображений |
|
|