Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > VB6 > Подсчет пятен


Автор: Mephisto 4.9.2003, 17:57
Люди, есть вопрос. Как можно посчитать количество пятен на рисунке? Сложность в том, что исходной картинкой является фотография, и пятна имеют разный размер.
Спасибо всем кто ответит.

Автор: cardinal 4.9.2003, 21:06
Если под пятнами ты подразумеваешь темные места на картинке, то предется выдумывать какой нибудь хитрый алгоритм (врятли ты готовый найдешь, я вещи и по стандартней не мог найти bored.gif). Мысля по этому поводу есть, а вот писать и тестировать предется тебе smile.gif.

Во первых есть два метода определить яркость цвета:
- яркость определяется по формуле:
(max + min) / 2,
при этом max и min это максимальное и минимальное значения из твоего RGB цвета. Что-то не получилось лучше сформулировать smile.gif . Объясняю на примере. Вот сидит у тебя pixel в bmp, ты смотришь какой у него цвет и получаешь (255, 255, 255), то есть белый. Максимальное значение - это 255 и минимальное тоже, поделили на два и получили 255, то есть ярче не будет. Ну и так далее. С красным (из стандартной palette) ты получишь яркость 127, то бишь среднюю яркость.
- А второй метод это определение яркости по формуле, которая определяет яркость наиболее близкою к яркости, которую воспринимаем мы. Вот формула:
Яркость = R * 0,3 + G * 0,59 + B * 0,11
Красный у тебя будет потемнее в два раза по этой формуле, а белый как был так и останется самым ярким (+/- погрешность если будешь работать без плавующей точки).

Во-вторых ты можешь сделать два буфера. При первом просмотре картинки ты запишешь в первый буфер яркости твоих точек, а при втором просмотре ты будешь писать в буфер номер пятна. Вобщем у тебя должен в конце концов быть такой результат:

-----------------------------------------------------
----11111------------------------------------------
-------111111------------------2222222---------
------11111111---------------------2222222----
----------1111111------------------22222222---
--------------------------------------------222222
-------------------------------------22222222222
----333333333------------------------------------
---------333333333-------------------------------
---------3333333333333-------------------------

Ну и соответственно самая большая цифра второго буфера это и есть количество пятен на твоем рисунке.

Успехов!

Автор: Black_Star 9.9.2003, 23:36
Я что-то не понял насчет определения яркости sad.gif...
Цитата
Вот сидит у тебя pixel в bmp, ты смотришь какой у него цвет и получаешь (255, 255, 255), то есть белый. Максимальное значение - это 255 и минимальное тоже

255 - максимум, верю.
Но 255 - минимум???
Найдем мы, например, число 100... получается (100+255)/2=177.5 ?
хм... это еще куда не шло... а найдем 1! 1 - это почти ничто, а получим в итоге 128! Это будет резко отличаться от действительности...

Предлагаю такой вариант, но он слишком долгий...
Просматриваем всю картинку...
A1=Point(x,y)
A2=Point(x+1,y)
A3=Point(x-1,y)
...
...
A9=Point(x+1,y+1)
Далее хитрым уравнением находим среднее значение всех цветов, это и будет цвет в точке х,у.

Автор: cardinal 10.9.2003, 12:20
Цитата
Я что-то не понял насчет определения яркости ...

Полностью согласен smile.gif.

Цитата
Найдем мы, например, число 100... получается (100+255)/2=177.5 ?
хм... это еще куда не шло... а найдем 1! 1 - это почти ничто, а получим в итоге 128! Это будет резко отличаться от действительности...

Дело в том, что число 100 или 1 мы не найдем smile.gif, потому что какждый pixel описывают три параметра. Для того, чтобы понять о чем здесь речь, предлагаю зайти в обыкновенный paint (paint->палитра->изменить палитру) и побаловаться с красками в палитре. Там ты увидишь разные значение красного, зеленого и синиго каналов, и яркость цвета. Так вот (min = "канал с наименьшим значением" + max = "канал с наибольшим значением") / 2 = яркость.

Цитата
255 - максимум, верю.
Но 255 - минимумconfused.gif

У белого цвета значения всех каналов равны, соответственно равны и значения min и маx.

Автор: Black_Star 10.9.2003, 19:52
Цитата
Дело в том, что число 100 или 1 мы не найдем , потому что какждый pixel описывают три параметра


smile.gif Как верно замечено, пиксел описывают 3 параметра. Енто и есть система RGB(красный, зеленый, синий). Они и представляют собою число типа Long, кот. хранятся в структуре BitMap. Насчет яркости там НИЧЕГО не сказано smile.gif

Цитата
Так вот (min = "канал с наименьшим значением" + max = "канал с наибольшим значением") / 2 = яркость.

(max + min) / 2
Максимальное значение - это 255 и минимальное тоже, поделили на два и получили 255


Вопрос. Почему яркость не бывает больше 240??? smile.gif

Цитата
Для того, чтобы понять о чем здесь речь, предлагаю зайти в обыкновенный paint (paint->палитра->изменить палитру) и побаловаться с красками в палитре


Предлагаю тоже smile.gif Яркость, как таковая никакой роли не играет, при изменении яркости меняется и сам цвет (см. на RGB) smile.gif


Автор: cardinal 11.9.2003, 03:07
Цитата
Вопрос. Почему яркость не бывает больше 240???

Ответ. А кто сказал, что paint так же яркость высчитывает, как я это предложил. Они сказали, что самое яркое значение - это 240, вот и все.

Цитата
Яркость, как таковая никакой роли не играет, при изменении яркости меняется и сам цвет (см. на RGB)

Ну а тут мы уже от темы отклоняемся smile.gif . Человек хочет пятна считать, соответственно яркость цвета тут играет роль.

Автор: Black_Star 11.9.2003, 23:04
Да, но понятие яркости такое размытое...
Яркость - не что иное, как сам цвет. Просто надо высчитывать значение соотв. цвета (0-255). И ничего делить не надо smile.gif
Возьми просто красный RGB(255,0,0)
но он может быть и RGB(100,0,0) просто кажется, что тускнее...
Но это изменение не яркости, а самого цвета!
А потому вычислить его яркость или неяркость нереально...
В моем 1м примере я предлагал сравнивать текущую точку с окружающими... Мотом брать "среднее". Но это будет типа метода Blur.
А для бооольших пятен надо ваще нечто выдумывать.... confused.gif
А то, что менять яркость.... приведет к ZOrder картинки smile.gif

Автор: cardinal 12.9.2003, 01:07
Цитата
Да, но понятие яркости такое размытое...

Ничего тут размытого нет! Как же dithering работает, если яркость - это размытое понятие?
Цитата
Просто надо высчитывать значение соотв. цвета (0-255). И ничего делить не надо.

Ну тогда напиши, как ты хочешь высчитывать это значение соотв. цвета (0-255). smile.gif

Автор: Black_Star 12.9.2003, 14:43
Цитата
Ну тогда напиши, как ты хочешь высчитывать это значение соотв. цвета (0-255).

А что там сложного?
RGB=&h980000 ,т.е. красный равен 155...
надо умеличить его "яркость" ставь. например 200... И что, сложно?
Но это не яркость! Это изменение самого цвета!!!

Автор: cardinal 12.9.2003, 15:59
Цитата
Но это изменение не яркости, а самого цвета!
А потому вычислить его яркость или неяркость нереально...

Я же вычисляю а ты говоришь нереально smile.gif.
Ладно, переходим к практике.
Вот есть у тебя на картинке круг цвета RGB(236,102,79), внутри него есть еще один круг меньшего диаметра - его цвет RGB(207,50,22), внутри него есть еще один круг (тоже меньшего диаметра) цвета RGB(146,35,16).
Так вот круг в самом центре очень темный, соответсвенно это и есть пятно. Используя метод (min+max)/2, получаем для трех кругов такие значения: 157, 114, 81. Соответсвенно мы можем сказать, что все что темнее 100 (<100) - это пятна. А теперь твоя очередь, Black_Star потому, что я так и не въехал, что ты предлагаешь делать. Вот еще раз то, что ты написал:
Цитата
А что там сложного?
RGB=&h980000 ,т.е. красный равен 155...
надо умеличить его "яркость" ставь. например 200... И что, сложно?



Автор: -Mikle- 13.9.2003, 12:41
Black_Star, cardinal абсолютно прав. Естественно для реального значения цвета разные RGB, но задача в том, чтобы определить темнее-светлее. Если рассматривать просто составляющие RGB, то ты не сможешь определить насколько один цвет темнее-светлее другого. Поэтому нужна формула, которая взяв три составляющие, вернула одно число. Наиболее верный результат яркости будет по известной всем формуле: Яркость = R * 0,3 + G * 0,59 + B * 0,11, упомянутой cardinal'ом, так как даст разный результат для значений: RGB(0,0,255) и RGB(0,255,0).
cardinal, + за терпеливость smile.gif

Автор: -Mikle- 13.9.2003, 12:49
Ну вот... воткнули проверку... теперь тебе нет плюса за терпеливость, простите, еще 440 сообщений надо, чтоб я мог человеку репутацию поднять... smile.gif.
Admin, не многовато-ли 500? Может хотя-бы 100 сделаешь? Если чел ответил 100 раз, значит он уже не просто "прохожий" на форуме... Ну да ладно, решать тебе... smile.gif

Автор: Black_Star 14.9.2003, 04:07
Темнее/светлее понятно... 3 составляющие никто рассматривать не собирался smile.gif)))
sad.gif(( Народ! Вы хоть понимаете за что я борюсьconfused.gifconfused.gif
Нет такого в действительности - ЯРКОСТИ !!!
Нету... и не будет... это просто цвет... у пущай он хоть триганом. фо-ми высчитывается, всеравно это не яркость, а цвет... просто светлее... Вай...
Не интересно с вами спорить - уперлись! smile.gif
Ладно, каждый остался при своих интересах smile.gifsmile.gifsmile.gif...

Автор: cardinal 14.9.2003, 16:20
Цитата
...это просто цвет..

Хорошо, взяли красный RGB(255,0,0). Посчитали то, что ты называешь цветом
Цитата
просто светлее
по формуле (min + max)/2 и получили (255 + 0)/2 = 127. А теперь вопрос: какой это цвет?
Конечно уперлись smile.gif , но хочется же знать что ты нам сказать то хочешь smile.gif

Автор: Black_Star 14.9.2003, 20:32
127,0,0 - красный. Однозначно smile.gif
0,127,0 - зеленый... и т.д.

Автор: cardinal 14.9.2003, 21:13
Так цвет получается неопределенный! Какой все таки цвет ты получаешь (один цвет): красный или зеленый?
Не красный и не зеленый, а цвет с яркостью 127 smile.gif .

Автор: Black_Star 14.9.2003, 21:26
:Е Достал... пусть будет ЯРКОСТЬ !!!
Но если сам цвет 255, то яркость 127 - "тусклость" !
Это ладно... Возьми цвет желтый RGB(255,255,0)...
То RGB(127,127,0) похож на темный желтый, но ужасно...

Автор: -Mikle- 15.9.2003, 17:09
Вы друг друга не понимаете smile.gif
cardinal, Black_Star прав, он говорит о том, что в RGB нет такого понятия как яркость, есть цвет из разных уровней 3 составляющих.
Black_Star, cardinal прав, он совсем и не доказывает что есть яркость у RGB, он просто говорит что пятно, для нашего глаза, это такой цвет, который при переводе в серые полутона, воспринимается нашим глазом темнее, чем другие. Например зеленый воздействует на сетчатку "мощнее", чем синий.

Вообще тема - это подсчет пятен. Реализовать это проще всего рассматривая картинку как черно-белое изображение, не вдаваясь в то, какого цвета сами пятна. В ЧБ картинке все три составляющие равны, и определяют, как бы, яркость белого цвета. Ты прав Black_Star, с позиции программы это просто разные цвета, но мы ищем ПЯТНА, которые может увидеть наш глаз на чб картинке, а это значит, что нам надо найти места, которые для глаза темнее, т.е. значение любой из 3 составляющих ЧБ изображения, например, меньше 100. cardinal просто берет цвет и сразу рассматривает его как черно-белую точку, называя полученное значение яркостью(т.е. насколько эта точка для нашего глаза темнее-светлее). Вот и все! smile.gif
Цитата
Но если сам цвет 255, то яркость 127 - "тусклость" !
Это ладно... Возьми цвет желтый RGB(255,255,0)...
То RGB(127,127,0) похож на темный желтый, но ужасно...
Ты не правильно понял, вот как должно это использоваться:
Цитата
Ф-ла: Q = R*0.3+G*0.59+B*0.11
у красного(255,0,0) Q=76.5, надо рассматривать цвет не (76.5, 0, 0) а (76.5, 76.5, 76.5)
у желтого (255,255,0) Q=226.95, надо рассматривать цвет не (226.95, 226.95, 0) а (226.95, 226.95, 226.95)@
Я тут их немного расскрасил для наглядности(чтоб прочитать выделите цитату до символа "@")
Удачи! adv/76.gif

Автор: Mephisto 15.9.2003, 17:26
-Mikle- прав разница между яркостью и цветом не так уж и важна. Предложение -Mikle-а перевести в ч/б я уже пробовал. Напомню, что искомая картинка это отсканированая фотография из электромикроскопа sad.gif . Очень много мелких точек которые комп воспринимает как пятна. Я уже пробовал создавать доверительный интервал размера пятен, но как вы понимаете получается уж очень громоздко. notify.gif

Вообще есть идея: при встрече пятна изучать его размеры, затем брать его в простую фигуру(например круг) и заливать его каким-либо цветом например vbGreen, при следуещей встрече с vbGreen_ом просто проходить мимо. В результате количество таких заливок и будет искомое кол-во пятен.

Может у кого есть идеи проще?exclamation.gif Спасибо.

Автор: Mephisto 18.9.2003, 18:01
Люди, нужны ещё идеи. baaa.gif

Автор: cardinal 18.9.2003, 20:07
Я если честно пока не понял, почему тебе не подошла та идея, которую я тебе еще в начале темы написал. Если картинки, которые ты сканируешь не очень большие, то кинь мне их на ящик, чтобы я понимал, что надо сделать получше. А если они здоровые, то вырежи фрагмент и кинь его на ящик. У меня просто подключение к инету не самое быстрое, да и ящик маленький sad.gif

Автор: Mephisto 22.9.2003, 18:01
OK в скором времени постараюсь вытащить фото в инет и сделать его доступным для всех. bored.gif

Автор: Mephisto 27.9.2003, 14:00
Цитата
Я если честно пока не понял, почему тебе не подошла та идея, которую я тебе еще в начале темы написал

Идея конечно супер, но....
Цитата
ты можешь сделать два буфера. При первом просмотре картинки ты запишешь в первый буфер яркости твоих точек, а при втором просмотре ты будешь писать в буфер номер пятна. Вобщем у тебя должен в конце концов быть такой результат:

-----------------------------------------------------
----11111------------------------------------------
-------111111------------------2222222---------
------11111111---------------------2222222----
----------1111111------------------22222222---
--------------------------------------------222222
-------------------------------------22222222222
----333333333------------------------------------
---------333333333-------------------------------
---------3333333333333-------------------------

Ну и соответственно самая большая цифра второго буфера это и есть количество пятен на твоем рисунке.

Хорошо, но есть вопрос: как при переходе на следующую строчку определить является ли найденое пятно продолжением первого, либо это уже пятно номер 3? notify.gif

Автор: cardinal 27.9.2003, 17:13
Ты бегаешь по строчкам слева направо, соответственно если слево от точки стоит цифра, то если if по темноте проходит, текущая точка будет с этим же номером. Если слева пусто, то ты смотришь на строчке выше. Если ты там найдешь на позициях (текущая точка - ширина bmp - 1) или (текущая точка - ширина bmp) или (текущая точка - ширина bmp + 1) каую нибудь цифру, то и текущей точке ты присваиваешь эту цифру, если нет, то это новое пятно.

Автор: maxim1000 28.9.2003, 09:04
Цитата
Ты бегаешь по строчкам слева направо, соответственно если слево от точки стоит цифра, то если if по темноте проходит, текущая точка будет с этим же номером. Если слева пусто, то ты смотришь на строчке выше. Если ты там найдешь на позициях (текущая точка - ширина bmp - 1) или (текущая точка - ширина bmp) или (текущая точка - ширина bmp + 1) каую нибудь цифру, то и текущей точке ты присваиваешь эту цифру, если нет, то это новое пятно

еще нужно предучмотреть механизм объединения пятен:
это придется делать в случае U-образных пятен
например, обработанные строки будут такие:
00000000000000000000
00000111100000220000
00001111100022222000
00000111100022200000
00000001110022200000
а следующая строчка:
000000000*****000000

Автор: cardinal 28.9.2003, 12:47
Да, maxim1000, есть такое дело. Спасибо, за дельный совет!
Цитата
еще нужно предусмотреть механизм объединения пятен

А механизм прост. Надо только переделать немного то, что я описал сверху smile.gif.

Ты бегаешь по строчкам слева направо, соответственно если слево от точки стоит цифра, то если if по темноте проходит, текущая точка будет с этим же номером. Если слева от точки стоит цифра и ты находишь на строчке выше на позициях (текущая точка - ширина bmp - 1) или (текущая точка - ширина bmp) или (текущая точка - ширина bmp + 1) какую нибудь цифру, то значит мы имеем U-образное пятно. Ту цифру, которую мы нашли сверху (и остальные такие же в буфере) мы заменяем на цифру, которая находится слева от точки.
Если слева пусто, то ты смотришь на строчке выше. Если ты там найдешь на позициях (текущая точка - ширина bmp - 1) или (текущая точка - ширина bmp) или (текущая точка - ширина bmp + 1) какую нибудь цифру, то и текущей точке ты присваиваешь эту цифру, если нет, то это новое пятно.

Ну и буфер (мне вот сейчас в голову пришло) надо сделать на две точки шире, чем сама картинка, тогда не надо будет бесконечно проверять на краю ты находишься или нет. Начинать надо в правильном месте и прыгать по строчкам тоже.

Автор: Mephisto 29.9.2003, 15:12
Спасибо всем кто ответил! Проблема подсчета пятен почти реализована. Осталось только тестировать.

Поступила новая задача, более сложная:
Имеется более плотная упаковка, необходимо так же подсчитать количество. Но сдесь это гораздо сложнее выполнить. Ну вобщем сами смотрите...

user posted image

Разные размеры картинок:
http://grafitchem.narod.ru/Small_Grafit.htm 75x100 (3.8 kb)
http://grafitchem.narod.ru/Resize_of_Grafit.htm 301x400 (32.9 kb)
http://grafitchem.narod.ru/Grafit.htm 2029x2696 (399.3 kb)

Если есть какие идеи, то...
За раннее спасибо.

Автор: cardinal 29.9.2003, 15:50
Цитата
Test image!

Ну и что нам с ним делать? Ты сам писать функцию начинай, а если что поможем!

Автор: Mephisto 29.9.2003, 17:16
Цитата
Цитата
Test image!

Ну и что нам с ним делать?

Да, прикольно получилось. tounge.gif
Это была версия для редактирования. Если картинка не подгружается, то можете посмотреть картинку по указанным адрессам. biggrin.gif

Автор: cardinal 29.9.2003, 22:13
Дааааа... Пятна оказывается не разделены четко, что делает все немного сложнее.
Ну тогда есть такое предложение:
Бегаешь по строчкам и ищешь какую нибудь светлую точку. Это будет что-нибудь типа середины пятна. От этой точки ты идешь вправо, вниз, влево и вверх пока не наткнешься на темную точку. Эти темные точки будут крайними точками пятна. Потом ты объединяешь эти четыре крайних точки, делая из них например прямоугольник. Этот прямоугольник будет приблизительно площадью, которую занимает пятно. Ну а потом, как ты уже и говорил можешь его залить, чтобы потом ясно было, где ты уже пятно отметил. Ну и так далее... Короче главное тут выбрать светлую границу и темную границу по которым ты и будешь определять "середина" это пятна или крайняя точка. В конце концов количество заливок - это и есть кол-во пятен +/- столько-то пятен (зависит от размера картинки). Но это дело такое. В конце концов потом ты можешь пробежать картинку четыре раза: с верхней левой точки, с верхней правой точки, с нижней левой точки и с нижней правой точки (ну чтобы каждый раз получались разные заливки), а результаты поделить на четыре. Я думаю результат будет неплохим.
Только вот жалко тебя omg.gif - средства отладки в VB для таких задач не предусмотрены, но это не значит, что сделать все что я написал невозможно, просто запаришься ты пока добьешься того, что все будет правильно работать.
Успехов!

Автор: Mephisto 1.10.2003, 15:46
Спасибо тебе cardinal за идею. Знаешь, ты почти прочитал мои мысли. smile.gif Особенно по поводу светлых пятен и нахождения центра. Только единственное отличие в том, что яхочу брать предположительное пятно не в квадрат, а в круг (потому что там присутствуют довольно большие экземпляры).
Также совпала почти реализованная идея на счет углов. Я пытаюсь пройти по картинке сначала сверху-вниз, а затем со всех углов. smile.gif

Автор: neutrino 2.10.2003, 11:09
Можно вопрос: на этой картинке пятна - это эти выпоклости или что? И тебе надо подсчитать количество выпуклостей?

Автор: Mephisto 2.10.2003, 16:27
Цитата
И тебе надо подсчитать количество выпуклостей?

Да! Плюс (в идеале) подсчитать площадь. wow.gif

Автор: cardinal 2.10.2003, 17:50
Цитата
Только единственное отличие в том, что я хочу брать предположительное пятно не в квадрат, а в круг (потому что там присутствуют довольно большие экземпляры).

А я про квадрат ничего не говорил smile.gif, я говорил про прямоугольник. Не советую рисовать "круги"! Во-первых запаришься "рисовать", а во-вторых точнее не будет smile.gif.
Вот так...

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)