Выкладываю обещанный скрипт для проверки наличия битых пикселей на матрице. Да кому он нужен, когда можно глазками все посмотреть? Он может пригодиться при покупке б/у фотоаппаратов через интернет, или для выбора лучшего фотоаппарата из нескольких, например, в магазине
Для начала надо заполучить RAW'ки, сделанные в максимальном разрешении, в режиме приоритета выдержки, в режиме ручной фокусировки с закрытым объективом (крышечку с объектива не снимаем). Чтобы было какое-то единообразие, пусть ISO пусть будет 100. В интернете встречаются рекомендации по установке выдержки в 3-5 секунд... Я-перфекционист, хочу, чтобы выдержка была 10 секунд.
Полученный "черный" кадр, конечно, можно и глазками посмотреть, но на дворе 21-й век! Поэтому немного схитрим.
Открываем RAW-файл любом подходящем графическом редакторе. В моем случае любым подходящим оказался Lightroom. RAW-файл экспортируем в PSD в формате 16-битного sRGB.
Теперь пару слов о том, что делает скрипт.
В конце PSD файла в формате RRR GGG BBB находятся данные нашей картинки. Помним, что мы конвертировали наш файл в формате 16-битного sRGB. Обращаем внимание на то, что у нас структура файла не RGBRGBRGB... а RRRRRR...GGGGG...BBBBB. Я не обратил на это в первый раз внимания, за что и поплатился... :о)
Скрипт читает заголовок файла, откуда получает информацию о размерах картинки и расположении блока Image Data Section, и начинает читать по два байта данные, пробегая массив данных RRRRR, затем GGGGG и наконец BBBBB, попутно "запоминая" элементы, яркость которых превышает указанный нами порог и выводит данные об обнаруженных точках в файл. Выводятся данные о координатах точек и яркости каналов, позволивших себе выделиться на общем фоне. :о).
На моем ноуте первоначальный вариант скрипта разбирал 12 миллионов пикселей более чем за 340 секунд. Сейчас 17 миллионов пикселей скрипт разбирает чуть более чем за 90 чекунд. Но мне кажется, что и 90 секунд - не предел.
Ну а теперь, собственно, сам скрипт.
//Каждый цвет может иметь интенсивность от 0 до 65535 и кодируется 2 байтами. //Блок с данными находится в конце файла. //Перед ним блоки переменной длины, читаем заголовки. //Ищем точки, в которых одна из компонент R,G или B превышает порог, //заданный в параметрах при запуске скрипта. //Пороговое значение задается в процентах. // $reshandle=fopen($argv[1]."-".$argv[2].".res",'w'); //Открываем файл для резудбтатов $start_time=time(); //Фиксируем время старта скрипта. $header=array(); $handle=fopen($argv[1],'r'); //Открываем файл формата PSD, указанный в параметрах $resarr=array(); $width=0; //Длина картинки $height=0; //Высота картинки $pixcnt=0; $limit=(int)((65535*$argv[2])/100); //Рассчитываем пороговое значение $cur_pos=0; //Текущая позиция в файле $content; //А сюда будем читать байты (2 шт), отвечающие за один пиксель $shine_num=0; //Счетчик "битых" пикселей //В этом блоке читаем заголовок PSD файла и вытаскиваем оттуда размеры картинки for ($i=0;$i<26;$i++) {$byte = fread($handle,1); $header[$i]=$byte; } $bh=array($header[14],$header[15],$header[16],$header[17]); $bw=array($header[18],$header[19],$header[20],$header[21]); $height=HEX_DEC_CONVERT($bh); $width=HEX_DEC_CONVERT($bw); $pixcnt=$height*$width; //Выводим полученную информацию в файл fwrite($reshandle,"Width (pxl): ".$width."\r\n"); fwrite($reshandle,"Height (pxl): ".$height."\r\n"); fwrite($reshandle,"Size (pxl): ".$pixcnt."\r\n=====================\r\n"); //Пойдем по-взрослому, с начала файла, читая заголовки блоков файла $cur_pos=$cur_pos+26; echo $cur_pos."\r\n"; //Color Mode Data Section fseek($handle,$cur_pos); for ($i=0;$i<4;$i++) {$byte = fread($handle,1); $farr[$i]=$byte; } $cur_pos=ftell($handle)+HEX_DEC_CONVERT($farr); echo $cur_pos."\r\n"; fseek($handle,$cur_pos); //Image Resources Section fseek($handle,$cur_pos); for ($i=0;$i<4;$i++) {$byte = fread($handle,1); $farr[$i]=$byte; } $cur_pos=ftell($handle)+HEX_DEC_CONVERT($farr); echo $cur_pos."\r\n"; fseek($handle,$cur_pos); //Layer and Mask Information Section fseek($handle,$cur_pos); for ($i=0;$i<4;$i++) {$byte = fread($handle,1); $sarr[$i]=$byte; } $cur_pos=ftell($handle)+HEX_DEC_CONVERT($sarr)+2; echo $cur_pos."\r\n"; fseek($handle,$cur_pos); $tmp_arr=array(); //==================== $i=0; for($y=0;$y<$height;$y++) {for($x=0;$x<$width;$x++) { //читаем данные по одной точке - 2 байт. $content=fread($handle,2); $tmp_arr[0]=$content[0]; $tmp_arr[1]=$content[1]; $R=HEX_DEC_CONVERT($tmp_arr); //Сравниваем с пороговым значением. //Если есть необходимость - сохраняем в массиве // координаты и значения компоненты RGB if ( ($R>$limit) ) {$resarr[$x][$y]['R']=$R; $resarr[$x][$y]['G']=null; $resarr[$x][$y]['B']=null; } } } for($y=0;$y<$height;$y++) {for($x=0;$x<$width;$x++) { //читаем данные по одной точке - 2 байт. $content=fread($handle,2); $tmp_arr[0]=$content[0]; $tmp_arr[1]=$content[1]; $G=HEX_DEC_CONVERT($tmp_arr); if ( ($G>$limit) ) {$resarr[$x][$y]['R']=null; $resarr[$x][$y]['G']=$G; $resarr[$x][$y]['B']=null; } } } for($y=0;$y<$height;$y++) {for($x=0;$x<$width;$x++) { //читаем данные по одной точке - 2 байт. $content=fread($handle,2); $tmp_arr[0]=$content[0]; $tmp_arr[1]=$content[1]; $B=HEX_DEC_CONVERT($tmp_arr); if ( ($B>$limit) ) {$resarr[$x][$y]['R']=null; $resarr[$x][$y]['G']=null; $resarr[$x][$y]['B']=$B; } } } //Разбор массива и вывод результатов в файл reset($resarr); $R=""; $G=""; $B=""; while (list($key,$val)=each($resarr)) { while (list($skey,$sval)=each($resarr[$key])) {if (!is_null($sval['R'])) {$R=" RED: ".$sval['R'];} if (!is_null($sval['G'])) {$G=" GREEN: ".$sval['G'];} if (!is_null($sval['B'])) {$B=" BLUE: ".$sval['B'];} fwrite($reshandle,"\r\nX: ".$key."; Y: ".$skey." ".$R.$G.$B); $shine_num++; } } //Цикл обработки закончился, выводим результаты работы fwrite($reshandle,"\r\n================================\r\n"); fwrite($reshandle,"\r\nBrightness: ".$argv[2]."%"); fwrite($reshandle,"\r\nNumber of shine pixels :".$shine_num); fwrite($reshandle,"\r\nWorking time (sec):".(time()-$start_time)); //echo ftell($handle)."\r\n"; fclose($handle); fclose($reshandle); //=================================================== //Переводим значения из двухбайтного HEX в DEC function HEX_DEC_CONVERT(array $arg) {$result=0; $cnt=count($arg); //echo $cnt."\r\n"; for ($f=$cnt;$f>0;$f--) {$result=$result+ord($arg[$f-1])*pow(256,$cnt-$f); } return $result; }
Чуть не забыл. Запускаем скрипт с параметрами. Первый параметр - имя файла. Второй параметр - процент.
php.exe shinepxl.php 5d.psd 5
На выходе получим файл с именем 5d.psd-5.res
Содержимое файла:
Width (pxl): 5184 Height (pxl): 3456 Size (pxl): 17915904 =============================================================== X: 24; Y: 2105 RED: 64646 =============================================================== Brightness: 40% Number of shine pixels :1 Working time (sec):93
В файле ширина, высота, общее количество точек. Потом перечисляются точки, у которых хотя бы одна составляющая R,G или B превышает заданное значение. Начало координатных осей - верхний левый угол.
В конце - пороговое значение, число найденных точек и время обработки.
Как видим, в примере имеем один битый пиксель, светящийся красным.
Вот, собственно, и все.
Комментариев нет:
Отправить комментарий