Страница: 1 | 2 | 
		
		 
			   
			 
			 
			 
			 
			
 
  
		
     
  
    
Вопрос: Попиксельное сравнение картинок
     
    
Добавлено: 07.06.10 13:36
     
      
  
				
			  
					 
			
				 
    
		
       
    
Автор вопроса:  
    
 Spiritsun
      
       
  
Облазил инет, ничо толкового не нашел. Помогите, пж., как очень быстро сравнить битмап в памяти? Средствами getpixel через цыклы - это долго. Пробовал Object.Equals, он сравнивает теги, а не нутро. Может есть какие внутренние команды, которые, например, сравнивали бы битовые представления объектов в памяти не трогая теги?
 
    
Куски имеют одинаковый размер. Интересует только нутро.
				
		
		
					 
			
				 
  
		
     
  
    
Ответы
     
    
Всего ответов: 28
     
      
  
		
	  
			 
	
		 
    
       
    
Номер ответа: 1 
      
Автор ответа:
 EROS
![]()
![]()
![]()
![]()
Вопросов: 58
Ответов: 4255
 Профиль |  | #1
       
Добавлено:  07.06.10 14:45
       
    
       
  
 
    
public System.IntPtr Scan0 { set; get; }
    Member of System.Drawing.Imaging.BitmapData
Summary:
Gets or sets the address of the first pixel data in the bitmap. This can also be thought of as the first scan line in the bitmap.
Returns:
The address of the first pixel data in the bitmap.
Тебе надо копать в эту сторону.. Используя эту фичу, ты получишь указатель на первый байт картинки в памяти, зная размеры картинки и ее глубину цвета ты сможешь создать байтовый массив нужного размера и скопировать в него картинку из памяти одним махом.. Таким образом ты получишь байтовый массив в котором представлена картинка.. Все что тебе останется - это лишь пробежаться одним циклом по массивам и сравнить байты. Если хоть одна пара байт различается то значит картинки не равны..
Если пишешь на С# и умеешь юзать unsafe код с указателями, то даже копировать ничего никуда не надо.. Надо будет лишь залочить картинки в памяти и провести сравнение прям на месте.. 
		
	  
			 
	
		 
    
       
    
Номер ответа: 2 
      
Автор ответа:
 Spiritsun
![]()
![]()
![]()
![]()
![]()
Вопросов: 15
Ответов: 44
      
 Профиль |  | #2
       
Добавлено:  07.06.10 16:08
       
    
       
  
Ага, хороший совет, пасиб. А есть ли команда сравнения блоков памяти? Ну чтоб не юзать циклы. Или как вариант не блоков памяти, а массивы, если обе картинки загнать туда.
 
    
		
	  
			 
	
		 
    
       
    
Номер ответа: 3 
      
Автор ответа:
 Artyom
![]()
![]()
![]()
![]()
![]()
![]()
![]()
Разработчик
Вопросов: 130
Ответов: 6602
      
 Профиль |  | #3
       
Добавлено:  07.06.10 16:35
       
    
       
  
Есть Enumerable.SequenceEqual
 
    
Поскольку работает через IEnumerable, то работать будет медленно, в место этого лучше сделать обычным циклом - будет быстрее.
Также можно еще быстрее сделать, если использовать unsafe указатели - не будет проверки выхода за границы массива.
		
	  
			 
	
		 
    
       
    
Номер ответа: 4 
      
Автор ответа:
 Сергей
![]()
![]()
![]()
![]()
![]()
![]()
![]()
![]()
![]()
ICQ: 558230345 
Вопросов: 7
Ответов: 91
      
 Профиль |  | #4
       
Добавлено:  07.06.10 16:36
       
    
       
  
попробуй посчитать контрольную сумму каждого рисунка и сравнить их
 
    
		
	  
			 
	
		 
    
       
    
Номер ответа: 5 
      
Автор ответа:
 Artyom
![]()
![]()
![]()
![]()
![]()
![]()
![]()
Разработчик
Вопросов: 130
Ответов: 6602
      
 Профиль |  | #5
       
Добавлено:  08.06.10 14:04
       
    
       
  
контрольная сумма здесь не нужна
 
    
		
	  
			 
	
		 
    
       
    
Номер ответа: 6 
      
Автор ответа:
 Сергей
![]()
![]()
![]()
![]()
![]()
![]()
![]()
![]()
![]()
ICQ: 558230345 
Вопросов: 7
Ответов: 91
      
 Профиль |  | #6
       
Добавлено:  08.06.10 16:53
       
    
       
  
 
    
Почему? Вопрос ведь в сравнении двух битмапов а не в выявлении различий. Посчитать контрольную сумму быстрее чем перебрать массив пикселей. Исравнить две суммы проще и быстрее.
		
	  
			 
	
		 
    
       
    
Номер ответа: 7 
      
Автор ответа:
 Sharp
![]()
![]()
![]()
![]()
![]()
![]()
![]()
![]()
![]()
![]()
Лидер форума
ICQ: 216865379 
Вопросов: 106
Ответов: 9979
      
 Web-сайт:  
 Профиль |  | #7
      
Добавлено:  08.06.10 18:10
       
    
       
  
Чтобы посчитать контрольную сумму, нужно пройтись по всему массиву. Если в файле всего одно отличие, по матожиданию достаточно пройти половину массива.
 
    
		
	  
			 
	
		 
    
       
    
Номер ответа: 8 
      
Автор ответа:
 EROS
![]()
![]()
![]()
![]()
Вопросов: 58
Ответов: 4255
 Профиль |  | #8
       
Добавлено:  08.06.10 18:28
       
    
       
  
 
    
А ну ка, просвяти.. как ты собираешься считать контрольную сумму картинки при условии что у них одинаковый размер?
		
	  
			 
	
		 
    
       
    
Номер ответа: 9 
      
Автор ответа:
 
![]()
![]()
![]()
![]()
Администратор
ICQ: 278109632 
Вопросов: 42
Ответов: 3949
      
 Web-сайт:  
 Профиль |  | #9
      
Добавлено:  08.06.10 19:06
       
    
       
  
А какая разница, какой у них размер? КоHрольная сумма будет разной при разности хоть одного бита.
 
    
		
	  
			 
	
		 
    
       
    
Номер ответа: 10 
      
Автор ответа:
 EROS
![]()
![]()
![]()
![]()
Вопросов: 58
Ответов: 4255
 Профиль |  | #10
       
Добавлено:  08.06.10 19:21
       
    
       
  
в том то и фишка, что автор каким то образом хочет посчитать сумму без испоьзования циклов.. вот мне и интересно как..
 
    
		
	  
			 
	
		 
    
       
    
Номер ответа: 11 
      
Автор ответа:
 VβÐUηìt
![]()
![]()
![]()
Вопросов: 246
Ответов: 3333
      
 Web-сайт:  
 Профиль |  | #11
      
Добавлено:  08.06.10 20:31
       
    
       
  
oO Просвятите, если я в чем то не прав:
 
    
В попу контрольную сумму (буэ). Туда же циклы (буээээээ!). Берем картинку А и картинку Б. Сначала сравниваем их размеры - если не совпадают - False. Затем, если они совпадают, накладываем А на другое с помощью BitBlt(.NET - DrawImageUnstretched) с битовой операцией такой, чтобы получалась разница (хоть какая-то, не помню там уже что именно, помню, что есть что-то такое 
 ). Так вот, таким образом, получаем изображение, на котором отмечены только несовпадающие пиксели. То есть, если такой-то пиксель васи А равен соответствующему пикселю васи Б, то выбранная нами (не случайно) битовая операция сделает что-нибудь, обращающее цвет этого пикселя в константу. Дальше делаем SetStretchBltMode (.NET - Smoothing = Smoothing.HighQuality, или как там), и StretchBlt (.NET - DrawImage) на битмап с новыми значениями ширины 1 и высоты 1, то есть ужимаем нашего васю в один пиксель. Далее смотрим: если, допустим, наша битовая операция делал все одинаковые пиксели черными (как наложение "разница" в фотошопе), а неодинаковые - нечерными (какими-нибудь), то степень отличия картинок изменяется отличием цвета новоиспеченного пикселя от черного цвета. Ну как? Понятно, что способ не очень точен (на изображениях от 16x16 пикселей 
 ), но зато, я полагаю, работает на порядки быстрее двух циклов. Остается только уточнить, есть ли хороший, годный битовый фильтр наложения для этой расты (не удержался). Смекнули?
		
	  
			 
	
		 
    
       
    
Номер ответа: 12 
      
Автор ответа:
 Сергей
![]()
![]()
![]()
![]()
![]()
![]()
![]()
![]()
![]()
ICQ: 558230345 
Вопросов: 7
Ответов: 91
      
 Профиль |  | #12
       
Добавлено:  09.06.10 09:53
       
    
       
  
есть подозрение, что вычисление контрольной суммы двух файлов стандартными средствами будет быстрее, чем "ручной" перебор двух массивов и пошаговое сравнение элементов массива. Во всяком случае из опыта это так. Хотя зависит от того, какой алгоритм подсчета используется.  
 
    
		
	  
			 
	
		 
    
       
    
Номер ответа: 13 
      
Автор ответа:
 Artyom
![]()
![]()
![]()
![]()
![]()
![]()
![]()
Разработчик
Вопросов: 130
Ответов: 6602
      
 Профиль |  | #13
       
Добавлено:  09.06.10 10:37
       
    
       
  
 
    
Посчитать контрольную сумму быстрее чем перебрать массив пикселей 
неверно
Исравнить две суммы проще и быстрее 
верно, при условии что контрольные суммы уже были заранее подсчитаны
Чтобы посчитать контрольную сумму, нужно пройтись по всему массиву. Если в файле всего одно отличие, по матожиданию достаточно пройти половину массива.  
Верно
oO Просвятите, если я в чем то не прав:
В попу контрольную сумму (буэ). Туда же циклы (буээээээ!). Берем картинку А и картинку Б. Сначала сравниваем их размеры - если не совпадают - False. Затем, если они совпадают, накладываем А на другое с помощью BitBlt(.NET - DrawImageUnstretched) с битовой операцией такой, чтобы получалась разница (хоть какая-то, не помню там уже что именно, помню, что есть что-то такое 
 ). Так вот, таким образом, получаем изображение, на котором отмечены только несовпадающие пиксели. То есть, если такой-то пиксель васи А равен соответствующему пикселю васи Б, то выбранная нами (не случайно) битовая операция сделает что-нибудь, обращающее цвет этого пикселя в константу. Дальше делаем SetStretchBltMode (.NET - Smoothing = Smoothing.HighQuality, или как там), и StretchBlt (.NET - DrawImage) на битмап с новыми значениями ширины 1 и высоты 1, то есть ужимаем нашего васю в один пиксель. Далее смотрим: если, допустим, наша битовая операция делал все одинаковые пиксели черными (как наложение "разница" в фотошопе), а неодинаковые - нечерными (какими-нибудь), то степень отличия картинок изменяется отличием цвета новоиспеченного пикселя от черного цвета. Ну как? Понятно, что способ не очень точен (на изображениях от 16x16 пикселей 
 ), но зато, я полагаю, работает на порядки быстрее двух циклов. Остается только уточнить, есть ли хороший, годный битовый фильтр наложения для этой расты (не удержался). Смекнули?  
Эта битовая операция называется XOR. В остальном - подходит как наглядное пособие по удалению гланд через жопу.
есть подозрение, что вычисление контрольной суммы двух файлов стандартными средствами будет быстрее, чем "ручной" перебор двух массивов и пошаговое сравнение элементов массива.  
Я бы на твоем месте не полагался на свою интуицию, по крайней мере пока опыт программирования не превысит 10 лет.
		
	  
			 
	
		 
    
       
    
Номер ответа: 14 
      
Автор ответа:
 Сергей
![]()
![]()
![]()
![]()
![]()
![]()
![]()
![]()
![]()
ICQ: 558230345 
Вопросов: 7
Ответов: 91
      
 Профиль |  | #14
       
Добавлено:  09.06.10 12:44
       
    
       
  
 
    
Скромность не позволяет, но  я пересилю себя. Программировать я начал еще в 1992 году. С ассемблера. 18 лет достаточно?
		
	  
			 
	
		 
    
       
    
Номер ответа: 15 
      
Автор ответа:
 Artyom
![]()
![]()
![]()
![]()
![]()
![]()
![]()
Разработчик
Вопросов: 130
Ответов: 6602
      
 Профиль |  | #15
       
Добавлено:  09.06.10 13:28
       
    
       
  
18 лет должно быть достаточно. Но странно, что человек, который программирует 18 лет (професионально? без перерывов?) так слабо разбирается в элементарных вещах.