Выкладываю обещанный скрипт для проверки наличия битых пикселей на матрице. Да кому он нужен, когда можно глазками все посмотреть? Он может пригодиться при покупке б/у фотоаппаратов через интернет, или для выбора лучшего фотоаппарата из нескольких, например, в магазине
Для начала надо заполучить 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 превышает заданное значение. Начало координатных осей - верхний левый угол.
В конце - пороговое значение, число найденных точек и время обработки.
Как видим, в примере имеем один битый пиксель, светящийся красным.
Вот, собственно, и все.
Комментариев нет:
Отправить комментарий