Что нового

Подсчет пикселей изображения

SET777

Новичок
Сообщения
51
Репутация
3
Есть ли какие-нибудь UDF в Автоите которые могут подсчитывать количество пикселей изображения всех имеющихся цветов. Проблема в следующем... Нужно подсчитать количество пикселей каждого цвета и вывести процент каждого цвета в изображении. Пробовал утилиту ImageMagick v6, но команда
Код:
C:\Image\convert c:\1.tif -format %c histogram: info:- c:\out.txt
записывает в out.txt на 10 мегабайт данных приблизительно следующего вида
Код:
# ImageMagick pixel enumeration: 344,498,255,rgb
0,0: (  0,  0,  0)  #000000  black
1,0: (  0,  0,  0)  #000000  black
2,0: (  0,  0,  0)  #000000  black
3,0: (  0,  0,  0)  #000000  black
4,0: (  0,  0,  0)  #000000  black
5,0: (  0,  0,  0)  #000000  black
6,0: (  0,  0,  0)  #000000  black
7,0: (  0,  0,  0)  #000000  black
8,0: (  0,  0,  0)  #000000  black
9,0: (  0,  0,  0)  #000000  black
10,0: (  0,  0,  0)  #000000  black
11,0: (  0,  0,  0)  #000000  black
12,0: (  0,  0,  0)  #000000  black
13,0: (  0,  0,  0)  #000000  black
14,0: (  0,  0,  0)  #000000  black
15,0: (  0,  0,  0)  #000000  black
16,0: (  0,  0,  0)  #000000  black
а нужно общее количество пикселей определенного цвета в одну строку. Помогите разобраться :wacko:
 

kaster

Мой Аватар, он лучший самый
Команда форума
Глобальный модератор
Сообщения
4,020
Репутация
626
попробуй использовать библиотеку GflAx и поиграться с функцией
Код:
object.GetColorAT(X as long, Y as long)

только сначала библиотеку надо зарегистрировать в системе.
 
Автор
S

SET777

Новичок
Сообщения
51
Репутация
3
:blink: Я с библиотеками еще не умею работать, пока это для меня темный лес :-\
Подсчет пикселей нужен для анализа снимков со спутника который фотографирует участки земли и определенным цветом обозначена влажность, сухость и.т.д. Вычислив количество пикселей нужного цвета в снимке можно высчитать процент например, влажности... Может это можно сделать как то по другому, не пересчитывая пиксели?
 

AZJIO

Меценат
Меценат
Сообщения
2,874
Репутация
1,194
SET777

сделал методом парсинга лога.

Код:
#include <Array.au3>
RunWait('C:\Image\convert c:\1.tif -format %c histogram: info:- c:\out.txt')
$text = FileRead('c:\out.txt')
If @error Then
	MsgBox(0, 'Сообщение', 'Отсутствует файл')
	Exit
EndIf

$a=StringRegExp($text, '(?i)(\#[0-9a-f]{6})', 3)
If @error Then
	MsgBox(0, 'Сообщение', 'Отсутствуют данные')
	Exit
EndIf
$out=_ArrayAm($a)
If Not @error Then _ArrayDisplay($out, 'подсчёт')


Func _ArrayAm(ByRef $data)
	Local $k, $i, $tmp
	Assign('/', 1, 1) ;для исключения пустых строк и не совпадения с локальными переменными
	If IsArray($data) Then
		$tmp=UBound($data)
		Local $out[$tmp][2]
		$k=0
		For $i = 0 To $tmp -1
			Assign($data[$i]&'/', Eval($data[$i]&'/')+1, 1)
			If Eval($data[$i]&'/') = 1 Then
				$out[$k][0]=$data[$i]
				$k+=1
			EndIf
		Next
		If $k = 0 Then Return SetError(1, 0, 0)
		ReDim $out[$k][2]
		$100=0
		For $i = 0 To $k -1
				$out[$i][1]=Eval($out[$i][0]&'/')
				$100+=$out[$i][1]
		Next
		For $i = 0 To $k -1
				$out[$i][1]=Round($out[$i][1]*100/$100, 2)
		Next
		Return $out
	Else
		Return SetError(1)
	EndIf
EndFunc
 

kaster

Мой Аватар, он лучший самый
Команда форума
Глобальный модератор
Сообщения
4,020
Репутация
626
ну вообще, время выполнения задачи растет пропорционально квадрату размерности изображения и линейно от кол-ва цветов. поэтому для достаточно большого изображения с более-менее приличной цветовой гаммой может уйти много времени.
1. дай какой-нибудь тестовый файл для проверки
2. сколько времени выполнялась задача при использовании
Код:
C:\Image\convert c:\1.tif -format %c histogram: info:- c:\out.txt
3. набросок программы при условии, что GflAx.dll зарегистрирован в системе
Код:
#include <array.au3>
$oGflAx = ObjCreate('GflAx.GflAx')
$hBitmap = $oGflAx.LoadBitmap('sample.tiff')
$nWidth = $oGflAx.Width
$nHeight = $oGflAx.Height
Local $aColors[$nHeight][$nWidth]
For $i = 0 to $nHeight - 1
	For $j = 0 to $nWidth - 1
		$aColors[$i][$j] = Hex($oGflAx.GetColorAt($i, $j))
	Next
	ConsoleWrite($i & @CRLF)
Next
_ArrayDisplay($aColors)
 
Автор
S

SET777

Новичок
Сообщения
51
Репутация
3
AZJIO Ваш вариант работает! :laugh: Спасибо! Каждый файл обрабатывается секунд 15 и чем больше цветов тем дольше идет подсчет как и писал Kaster, а файлов около 500. Можно ли как то этот процесс автоматизировать, указать папку с файлами и записывать все результаты в лог файл + к каждому результату дописывать название цвета. Как то так:
Код:
"Название файла"
[1]|#A37700|24.25 rgb(229,183,50)
[2]|#E5B732|51.04 black

Лог бывает такого содержания:
130,8: (  0,  0,  0)  #000000  black
131,8: (  0,  0,  0)  #000000  black
132,8: (229,183, 50)  #E5B732  rgb(229,183,50)
133,8: (229,183, 50)  #E5B732  rgb(229,183,50)
и не записывать результаты которые меньше одного, потому что в некоторых изображениях цветов бывает много, в малых количествах и список получается очень большим.

Kaster
1. Фотографии http://autoit-script.ru/index.php?action=downloads;sa=downfile&id=106
2. Секунд 13 не считая подсчета
3. Пробовал Ваш скрипт, работает. Он выводит все пиксели изображения как я понял? Как можно написать этот подсчет с примером выше. Это было бы вообще здорово, не использовать сторонние приложения.
 

kaster

Мой Аватар, он лучший самый
Команда форума
Глобальный модератор
Сообщения
4,020
Репутация
626
SET777 [?]
Он выводит все пиксели изображения как я понял?
да. по координатам. покапайся в справке библиотеки, там не много функций. разобраться труда не составит. возникнут вопросы по реализации той или иной идеи, пиши тут. посмотрю что можно сделать.
Как можно написать этот подсчет с примером выше
если ты хочешь, чтобы написали скрипт, то оформи в стол заказов. но вообще, сама идея ведь не сложная.
1. попиксельно проверять цвет картинки
2. анализировать цвет
3. по результатам анализа заполнять файл.

можно вносить детали, типа кол-ва попаданий того или иного цвета, и только при пороге выше определенной заполнять в массив. одним словом, экспериментируй.
 

AZJIO

Меценат
Меценат
Сообщения
2,874
Репутация
1,194
SET777
Это было бы вообще здорово, не использовать сторонние приложения.
Оно использует стороннее приложение. Тут важен факт скорости. Если 500*13/60=100 минут, то есть 1 час и 40 мин и тут важное значение имеет время. Какой утилитой быстрее, той и делать.

Вот пример, выдаёт результат с указанным количеством максимальных данных. В примере указано 10. Это немного увеличивает скорость скрипта, даже сортировка выполняется мгновенно.

Код:
#include <array.au3>
$max=10 ; количество данных наибольших значений
$oGflAx = ObjCreate('GflAx.GflAx')
$hBitmap = $oGflAx.LoadBitmap('Picture.jpg')
$out=_ArrayAm()
If Not @error Then _ArrayDisplay($out, 'Результат')
 
Func _ArrayAm()
	Local $k, $i, $j
	$nWidth = $oGflAx.Width
	$nHeight = $oGflAx.Height
	Assign('/', 1, 1)
	Local $out[$nWidth*$nHeight][2]
	Local $Search[$nWidth*$nHeight]
	$k=0
	ToolTip('Подсчитываем количества в переменные')
	For $i = 0 to $nHeight - 1
		For $j = 0 to $nWidth - 1
			$Colors = $oGflAx.GetColorAt($i, $j)
			Assign($Colors&'/', Eval($Colors&'/')+1, 1)
			If Eval($Colors&'/') = 1 Then
				$out[$k][0]=$Colors
				$k+=1
			EndIf
		Next
	Next
	If $k = 0 Then
		ToolTip('')
		Return SetError(1)
	EndIf
	ReDim $out[$k][2]
	$100=0
	ToolTip('Создаём массив данных')
	For $i = 0 To $k -1
			$out[$i][1]=Eval($out[$i][0]&'/')
			$Search[$i]=$out[$i][1]
			$100+=$out[$i][1]
	Next
	If $k<$max Then $max=$k
	Local $am[$max][2]
	For $i = 0 to $max-1
		$ind=_ArrayMaxIndex($Search, 1)
		$am[$i][0]=Hex($out[$ind][0])
		$am[$i][1]=$out[$ind][1]
		$Search[$ind]=0
	Next
	
	_ArraySort($am, 1, 0, 0, 1)
	For $i = 0 To $max-1
			$am[$i][1]=Round($am[$i][1]*100/$100, 2)
	Next
	ToolTip('')
	Return $am
EndFunc

Ну и конечный результат с обработкой файлов в папке, включая вложенные.

Код:
Global $Stack[50], $Stack1[50]
#include <Array.au3>

$max=10 ; количество данных наибольших значений
$FileEx='bmp;png' ; типы файлов
$PathPic="C:\WINDOWS" ; путь к каталогу
$FileLog = FileOpen(@ScriptDir&'\file.log',1)

$Text = ''
$timer=TimerInit()
FileFindNextFirst($PathPic)
While 1
	$tempname = FileFindNext($FileEx, 1)
	If $tempname = "" Then ExitLoop
	$Text &= $tempname & @LF
WEnd
If $Text="" Then
	MsgBox(0, 'Message', 'Файлов не найдено')
	Exit
EndIf
$aText=StringSplit (StringTrimRight($Text, 1), @LF)
ToolTip('Найдено '&$aText[0]&' файлов за '&Round(TimerDiff($timer) / 1000, 2) & ' сек')
_ArrayDisplay($aText, 'Файлы') ; эту строку можно удалить


For $i = 1 to $aText[0]
	$oGflAx = ObjCreate('GflAx.GflAx')
	$hBitmap = $oGflAx.LoadBitmap($aText[$i])
	$out=_ArrayAm($i)
	; _ArrayDisplay($out, 'out')
	$Text = $aText[$i]&@CRLF&@CRLF
	For $j = 0 to UBound($out)-1
		$Text&=$out[$j][0]&' - '&$out[$j][1]&@CRLF
	Next
	If Not @error Then
		FileWrite($FileLog, $text&@CRLF&@CRLF&@CRLF)
	EndIf
Next
FileClose($FileLog)
ToolTip('Готово')
Sleep(1000)
ToolTip('')

 
Func _ArrayAm($n)
	Local $k, $i, $j, $max2=$max
	$nWidth = $oGflAx.Width
	$nHeight = $oGflAx.Height
	Assign('/', 1, 1)
	Local $out[$nWidth*$nHeight][2]
	Local $Search[$nWidth*$nHeight]
	$k=0
	ToolTip($n&' - Подсчитываем количества в переменные')
	For $i = 0 to $nHeight - 1
		For $j = 0 to $nWidth - 1
			$Colors = $oGflAx.GetColorAt($i, $j)
			Assign($Colors&'/', Eval($Colors&'/')+1, 1)
			If Eval($Colors&'/') = 1 Then
				$out[$k][0]=$Colors
				$k+=1
			EndIf
		Next
	Next
	If $k = 0 Then
		ToolTip('')
		Return SetError(1)
	EndIf
	ReDim $out[$k][2]
	$100=0
	ToolTip($n&' - Создаём массив данных')
	For $i = 0 To $k -1
			$out[$i][1]=Eval($out[$i][0]&'/')
			$Search[$i]=$out[$i][1]
			$100+=$out[$i][1]
	Next
	If $k<$max Then $max2=$k
	Local $am[$max2][2]
	For $i = 0 to $max2-1
		$ind=_ArrayMaxIndex($Search, 1)
		$am[$i][0]=Hex($out[$ind][0])
		$am[$i][1]=$out[$ind][1]
		$Search[$ind]=0
	Next
	
	_ArraySort($am, 1, 0, 0, 1)
	For $i = 0 To $max2-1
			$am[$i][1]=Round($am[$i][1]*100/$100, 2)
	Next
	ToolTip('')
	Return $am
EndFunc






; Функции поиска файлов
Func FileFindNextFirst($FindCat)
	$Stack[0] = 1
	$Stack1[1] = $FindCat
	$Stack[1] = FileFindFirstFile($FindCat & "\*.*")
	Return $Stack[1]
EndFunc   ;==>FileFindNextFirst

;$mode=0 - файлы
;$mode=1 - типы файлов
;$mode=2 - каталоги
;$Level=  от 1 до 49
;$type = может иметь перечисление расширений, например exe;dll;com точнее $tempname = FileFindNext('exe;dll;com',1,1)
Func FileFindNext($type = 'log', $mode = 0, $Level = 49)
	While 1
		$file = FileFindNextFile($Stack[$Stack[0]])
		If @error Then
			FileClose($Stack[$Stack[0]])
			If $Stack[0] = 1 Then
				Return ""
			Else
				$Stack[0] -= 1
				ContinueLoop
			EndIf
		Else
			If StringInStr(FileGetAttrib($Stack1[$Stack[0]] & "\" & $file), "D") > 0 Then
				If $Stack[0] = $Level Then ContinueLoop
				$Stack[0] += 1
				$Stack1[$Stack[0]] = $Stack1[$Stack[0] - 1] & "\" & $file
				$Stack[$Stack[0]] = FileFindFirstFile($Stack1[$Stack[0]] & "\*.*")
				If $mode = 2 Then
					Return $Stack1[$Stack[0]]
				Else
					ContinueLoop
				EndIf
			Else
				If $mode = 2 Then ContinueLoop
				If $mode = 1 Then
					;If StringInStr (';'&$type&';', ';'&StringRight($Stack1[$Stack[0]] & "\" & $file, 3)&';')=0  Then
					If StringInStr (';'&$type&';', ';'&StringRegExpReplace($Stack1[$Stack[0]] & "\" & $file, '.*\.(\S+)', '\1')&';')=0  Then
						ContinueLoop
					Else
						Return $Stack1[$Stack[0]] & "\" & $file
					EndIf
				Else
					Return $Stack1[$Stack[0]] & "\" & $file
				EndIf
			EndIf
		EndIf
	WEnd
EndFunc   ;==>FileFindNext
 
Верх