Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

Как программно подсчитать количество пузырей на фото, Фото внутри.

548
03 мая 2008 года
Maximillian_Cavalera
157 / / 16.08.2007
как на такой картинке программно подсчитать сколько пузырей. Я думал считать их по бликам, однако я не понимаю как можно так отделить один пузырь от другого, для подсчёта. Желательно с примером кода.


[COLOR="Red"]от Модератора: Ты мне весь раздел уже запузырил...[/COLOR]
1.9K
04 мая 2008 года
andriano
474 / / 10.01.2008
В любом случае алгоритм нужно будет подстраивать при помощи каких-то коэффициентов.
Навскидку - алгоритм с двумя настроечными коэффициентами + ...дополнительно небольшая настройка.
Вот с этой дополнительной настройки и начнем:

1. Надо привести цветное изображение к полутоновому (серому). Какие подобрать коэффициенты при цветовых составляющих - одна возможность настройки.
2. После того, как изображение приведено к серому, необходимо выбрать уровень (1-й настроечный параметр), ниже которого все считать черным, а выше - белым.
3. Привести изображение к монохромному (черно-белому).
4. Пусть у нас основная масса черная, а блики, которые нужно считать - белые.
5. Проходим последовательно все строки изображения.
6. Если точка черная, ничего не делаем - переходмим к следующей.
7. Если точка белая - начинаем процедуру закраски.
8. Закрашиваем все белые точки смежные с найденной. Т.е. закрашиваем черным все белое пятно. Подсчитываем точки в этом пятне.
9. Если количество точек в пятне больше определенного количества (второй настроечный параметр), то учитываем это пятно при подсчете.
10. После закраски пятна переходим к следующей точке по очереди после той, с которой мы начинали закраску.

Количество учтенных пятен и должно равняться количеству пузырей.
Примечание: на шаге 8 у нас есть еще одна возможность настройки - считать либо не считать смежными точки, находящиеся по диагонали.
9
04 мая 2008 года
Lerkin
3.0K / / 25.03.2003
Программно приведи своё изображение к примерно такому виду (на рисунке). От него уже проще реализовывать твою идею...

З.Ы. Гы, блин... Галактики какие-то получились... :D
341
04 мая 2008 года
Der Meister
874 / / 21.12.2007
Наиболее крупные пузыри, скорее всего, будут чаще всего лопаться. Возможно предпочтение следует отдать всё-же маленьким пятнам.
548
05 мая 2008 года
Maximillian_Cavalera
157 / / 16.08.2007
Цитата: Lerkin
Программно приведи своё изображение к примерно такому виду (на рисунке). От него уже проще реализовывать твою идею...

З.Ы. Гы, блин... Галактики какие-то получились... :D



А можешь рассказать или кинуть ссылку на то как это сделать, а то облазил нет так ничего и не нашёл. Кстати это фильтр фотошопа Stamp?

1.9K
05 мая 2008 года
andriano
474 / / 10.01.2008
Цитата: Maximillian_Cavalera
А можешь рассказать или кинуть ссылку на то как это сделать, а то облазил нет так ничего и не нашёл. Кстати это фильтр фотошопа Stamp?

Собственно, именно этому посвящены первые 4 пункта моего предыдущего сообщения.

9
05 мая 2008 года
Lerkin
3.0K / / 25.03.2003
Цитата: Maximillian_Cavalera
А можешь рассказать или кинуть ссылку на то как это сделать, а то облазил нет так ничего и не нашёл. Кстати это фильтр фотошопа Stamp?


Нет, это не Photoshop (из него в png конвертил). Какая-то моя наработка (вроде как для heightmap) но исходники потерялись... :(
Да не сложно там, при желании - статей в сети уйма...

548
05 мая 2008 года
Maximillian_Cavalera
157 / / 16.08.2007
Lerkin, можешь кинуть ссылку или сказать какой запрос нужно вводить, а то я искал так ничего не нашёл.
9
05 мая 2008 года
Lerkin
3.0K / / 25.03.2003
Цитата: Maximillian_Cavalera
... а то я искал так ничего не нашёл.


Значит - не дано. Пост №2 смотри, и ищи как написано (по пунктам).

341
06 мая 2008 года
Der Meister
874 / / 21.12.2007
Первым этапом, наверное, должно быть преобразование цвета из RGB в HSV с последующим присвоением Saturation = 0 для каждого пиксела
1.9K
06 мая 2008 года
andriano
474 / / 10.01.2008
Цитата: Der Meister
Первым этапом, наверное, должно быть преобразование цвета из RGB в HSV с последующим присвоением Saturation = 0 для каждого пиксела


А зачем?

341
07 мая 2008 года
Der Meister
874 / / 21.12.2007
Цитата: andriano
А зачем?


За хлебом: так преобразовать цвета в градации серого проще.
Можно, в принципе, вааще ничего не преобразовывать, и использовать для получения картины бликов (вектор(точка.цвет)).длину, посчитанную по Пифу

1.9K
07 мая 2008 года
andriano
474 / / 10.01.2008
Цитата: Der Meister
За хлебом: так преобразовать цвета в градации серого проще.
Можно, в принципе, вааще ничего не преобразовывать, и использовать для получения картины бликов (вектор(точка.цвет)).длину, посчитанную по Пифу



"Проще", говоришь?
Во-первых, преобразование к градациям серого осуществляется по формуле:
Y = Wr*R + Wg*G + Wb*B
где Wr, Wg и Wb - весовые коэффициенты равные 0.30, 0.59 и 0.11 соответственно.
А ну-ка приведи код, который делает это "проще" через преобразование в HSV.

Во-вторых, в данной задаче преобразовывать в градации серого не требуется Требуется подобрать такие коэффициенты, при которых обеспечивается наиболее адекватный вариант подсчета.
Могу предложить, например, такме: Wr=0, Wg=0.5 и Wb=0.5.
Никакого отношения к градациям серого это иметь не будет, а результат может дать лучше.

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

548
08 мая 2008 года
Maximillian_Cavalera
157 / / 16.08.2007
Я уже разобрался с тем как привести изображение к чёрно-белому
Код:
procedure CollectBlackAndWhiteInfo(bmp : TBitmap; const rect : TRect);
var
  i, j : integer;
  line : PRGBTriple;
  r, g, b : byte;
begin
  for i := rect.Top to rect.Bottom - 1 do
  begin
    line := bmp.ScanLine;
    for j := rect.Left to rect.Right - 1 do
    begin
      r := line.rgbtRed;
      g := line.rgbtGreen;
      b := line.rgbtBlue;
      histogramInfo[j, i] := r shr 16 + g shr 8 + b;
      if (histogramInfo[j, i] >= level) then
        binaryImage[j, i] := 1
      else
        binaryImage[j, i] := 0;
      Inc(line);
    end;
  end;


level - порог, выше которого белое, ниже чёрное.

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

Код:
function TBubbleFinder.CountBubbles: integer;
var
  i, j, k, l : integer;
  numberOfBubbles : integer;
  hasNumberTwo : boolean;
begin
  numberOfBubbles := 0;
  for i := 0 to BINAR_Y_SIZE do
  begin
    for j := 0 to BINAR_X_SIZE do
    begin
      if (binaryImage[i, j] = 1) then
      begin
        hasNumberTwo := false;
        for k := i - 1 downto 0 do
        begin
          for l := j to BINAR_X_SIZE do
          begin
            if (binaryImage[k, l] = 0) then
            begin
              break;
            end
            else if (binaryImage[k, l] = 2) then
            begin
              hasNumberTwo := true;
            end;
          end;
        end;
        for k := i to BINAR_Y_SIZE do
        begin
          for l := j to BINAR_X_SIZE do
          begin
            if (binaryImage[k, l] = 0) then
            begin
              break;
            end;
            if (binaryImage[k, l] = 2) then
            begin
              hasNumberTwo := true;
            end;
            binaryImage[k, l] := 2;
          end;
          for l := j - 1 downto 0 do
          begin
            if (binaryImage[k, l] = 0) then
            begin
              break;
            end;
            if (binaryImage[k, l] = 2) then
            begin
              hasNumberTwo := true;
            end;
            binaryImage[k, l] := 2;
          end;
        end;
        if (not hasNumberTwo) then
        begin
          Inc(numberOfBubbles);
        end;
      end;
    end;
  end;
  result := numberOfBubbles;
end;
1.9K
09 мая 2008 года
andriano
474 / / 10.01.2008
Предложенный алгоритм описан в пунктах 5-10 второго поста. Работает для связных областей произвольной формы.
Чем он не устраивает?
548
10 мая 2008 года
Maximillian_Cavalera
157 / / 16.08.2007
Вот меня и интересует алгоритм закрашивания пятна.
9
10 мая 2008 года
Lerkin
3.0K / / 25.03.2003
Цитата: Maximillian_Cavalera
Вот меня и интересует алгоритм закрашивания пятна.


Чего ж тебя на каждом шаге пинать надо, а?
Тут смотри.

1.9K
10 мая 2008 года
andriano
474 / / 10.01.2008
Цитата: Maximillian_Cavalera
Вот меня и интересует алгоритм закрашивания пятна.

1. Заносишь первую точку в очередь.
2. Извлекаешь одну за другой точки из очереди, закрашивая их и занося в очередь их незакрашенных соседей.

9
11 мая 2008 года
Lerkin
3.0K / / 25.03.2003
Цитата: andriano
1. Заносишь первую точку в очередь.
2. Извлекаешь одну за другой точки из очереди, закрашивая их и занося в очередь их незакрашенных соседей.


Это любому идиоту понятно будет. А с мало-мальским примером или ссылочкой можно? Или только воздух сотрясать своими неземными познаниями?

1.9K
11 мая 2008 года
andriano
474 / / 10.01.2008
Цитата: Lerkin
Это любому идиоту понятно будет. А с мало-мальским примером или ссылочкой можно? Или только воздух сотрясать своими неземными познаниями?



Ну, когда все понятно, дополнительных вопросов не задают.

Вот мне, кстати, непонятно, чем алгоритм, находящийся по ссылке, лучше того же алгоритма, помещенного непосредственно в тело сообщения?

Кроме того, в тексте твоего сообщения чувствуется неприязнь. Хотелось бы знать, чем она обусловлена?

9
11 мая 2008 года
Lerkin
3.0K / / 25.03.2003
Цитата: andriano
...Кроме того, в тексте твоего сообщения чувствуется неприязнь. Хотелось бы знать, чем она обусловлена?


Отнюдь. Только содержательности в твоих постах мало. Если так будет продолжаться, тему закрою. С раздачей слонов, разумеется...

548
11 мая 2008 года
Maximillian_Cavalera
157 / / 16.08.2007
Цитата: andriano
1. Заносишь первую точку в очередь.
2. Извлекаешь одну за другой точки из очереди, закрашивая их и занося в очередь их незакрашенных соседей.


Я не совсем понимаю, можешь привести пример кода.

Lerkin, спасибо за ссылку, я прочитал, но не очень понял как это реализовать.

9
11 мая 2008 года
Lerkin
3.0K / / 25.03.2003
Цитата: Maximillian_Cavalera
Я не совсем понимаю, можешь привести пример кода.

Lerkin, спасибо за ссылку, я прочитал, но не очень понял как это реализовать.


Ты, вообще, хоть немного программить умеешь?

548
11 мая 2008 года
Maximillian_Cavalera
157 / / 16.08.2007
Вот я написал как говорил andriano. Работает отлично: все картини, что я ему показывал - всё правильно подсчитал. Однако я столкнулся с такой проблемой, когда начал использовать этот метод при работе камеры: программа подвисает при подсчёте числа пузырей. Я думаю это связано с тем, что из-за освещённости картинка представляется то много почти полностью белая, то почти полностью чёрная и он ставит в очередь слишком много пикселей
Код:
TPixel = packed record
    X, Y : integer;
  end;

function TBubbleFinder.CountBubbles: integer;
var
  i, j : integer;
  numberOfBubbles : integer;
begin
  numberOfBubbles := 0;
  for i := 0 to BINAR_Y_SIZE do
  begin
    for j := 0 to BINAR_X_SIZE do
    begin
      if (binaryImage[j, i] = 1) then
      begin
        if (OverflawFigure(j, i) >= minBubbleSquare) then
        begin
          Inc(numberOfBubbles);
        end;
      end;
    end;
  end;
  result := numberOfBubbles;
end;

function TBubbleFinder.OverflawFigure(a, b : integer) : integer;
var
  i, j : integer;
  figureSquare : integer;
begin
  PixelsArrayDownToZero;
  figureSquare := 1;
  Inc(queueOfPixelsLength);
  pixelsQueue[queueOfPixelsLength].X := a;
  pixelsQueue[queueOfPixelsLength].Y := b;
  while (queueOfPixelsLength >= 0) do
  begin
    i := pixelsQueue[queueOfPixelsLength].Y;
    j := pixelsQueue[queueOfPixelsLength].X;
    selectedPixels[j, i] := true;
    binaryImage[j, i] := 0;
    Dec(queueOfPixelsLength);
    if (binaryImage[j + 1, i] = 1) then
    begin
      figureSquare := MarkSelectedPixel(j + 1, i, figureSquare);
    end;
    if (binaryImage[j - 1, i] = 1) then
    begin
      figureSquare := MarkSelectedPixel(j - 1, i, figureSquare);
    end;
    if (binaryImage[j, i - 1] = 1) then
    begin
      figureSquare := MarkSelectedPixel(j, i - 1, figureSquare);
    end;
    if (binaryImage[j, i + 1] = 1) then
    begin
      figureSquare := MarkSelectedPixel(j, i + 1, figureSquare);
    end;
  end;
  result := figureSquare;
end;

function TBubbleFinder.MarkSelectedPixel(j, i,
  figureSquare: integer): integer;
begin
  if (not selectedPixels[j, i]) then
  begin
    Inc(figureSquare);
    selectedPixels[j, i] := true;
    Inc(queueOfPixelsLength);
    pixelsQueue[queueOfPixelsLength].X := j;
    pixelsQueue[queueOfPixelsLength].Y := i;
  end;
  result := figureSquare;
end;
548
11 мая 2008 года
Maximillian_Cavalera
157 / / 16.08.2007
Как можно по картинке сделать 3-д модель
9
11 мая 2008 года
Lerkin
3.0K / / 25.03.2003
[COLOR="Red"]Темы объединены.[/COLOR]
Maximillian_Cavalera, если создашь еще одну тему для своих пузырей - наказание последует незамедлительно.
[CENTER] [SIZE="5"][COLOR="Red"]Пузырим тут![/COLOR][/SIZE][/CENTER]
1.9K
11 мая 2008 года
andriano
474 / / 10.01.2008
1. Длина очереди не должна превосходить периметра картинки. Но советую "во избежание" и не делать ее меньше. Расход памяти по сравнению с памятью, расходуемой на картинку, все равно мизерный.
2. Если от одной картинки до другой есть сильные перепады яркости, советую перед обработкой строить для каждой картинки диаграмму, после чего привязывать границу раздела между черным и белым к определенной точка диаграммы.
548
15 мая 2008 года
Maximillian_Cavalera
157 / / 16.08.2007
А как можно обвести (пусть даже коряво) пузыри, вернее обрисовать границы пузырей.
1.9K
16 мая 2008 года
andriano
474 / / 10.01.2008
Цитата: Maximillian_Cavalera
А как можно обвести (пусть даже коряво) пузыри, вернее обрисовать границы пузырей.


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

548
16 мая 2008 года
Maximillian_Cavalera
157 / / 16.08.2007
Ссылку где про это почитать можно, можешь кинуть
1.9K
17 мая 2008 года
andriano
474 / / 10.01.2008
Цитата: Maximillian_Cavalera
Ссылку где про это почитать можно, можешь кинуть


Не могу.
Нет у меня такой ссылки.
Да и непонятно из твоего сообщения, какая именно ссылка тебе нужна.
Поэтому могу предложить сначала тщательно сформулировать, что именно тебе нужно, а затем скормить свою формулировку Гуглу. У него точно есть ссылки.

Могу предложить и альтернативный вариант (сам обычно пользуюсь именно им).
1. Попытаться выполнить поставленную задачу ручками.
2. Тщательно проанализировать и задокументировать свои действия.
3. На основании этих записей составить алгоритм.
4. Написать реализацию этого алгоритма на любом доступном ЯВУ и радоваться жизни.

548
17 мая 2008 года
Maximillian_Cavalera
157 / / 16.08.2007
Цитата:
В прнинципе, можно попытаться выделить области с максимальным градиентом, а потом провести скелетизацию, после чего избавиться от отдельных точек (в которые должны превратиться блики).



andriano, ты же это не от балды взял. Можешь скинуть ссылку на это или хотя бы сказать где ты такое узнал.
[COLOR="Red"]
from moderator: самое последнее предупреждение...[/COLOR]

1.9K
17 мая 2008 года
andriano
474 / / 10.01.2008
Цитата: Maximillian_Cavalera
andriano, ты же это не от балды взял. Можешь скинуть ссылку на это или хотя бы сказать где ты такое узнал.

Гм...
Если "балдой" ты называешь <свою> голову, то это твое право.
Я же не говорил ни о чем, до чего нельзя было бы додуматься своей головой. По крайней мере, я обычно так и делаю.
Единственное, что я "позаимствовал", это сам термин "скелетизация", на что и готов дать ссылку: http://forum.sources.ru/index.php?showtopic=231182

PS. В оригинале термин звучит "скелетонизация", но, думаю, более адекватный русский перевод именно "скелетизация". (skeleton - скелет).

548
18 мая 2008 года
Maximillian_Cavalera
157 / / 16.08.2007
"Взять от балды" - это выражение, означающее, ответить что-то более менне правдоподобное на заданный вопрос, но не всегда соответствующее действительности.
33K
21 мая 2008 года
seska
26 / / 10.04.2008
http://www.intuit.ru/department/graphics/rastrgraph/9/
Графические фильтры, позволяющие выделять контуры. От простого градиентного, до алгоритма Кэнни.
Не уверен, подойдет ли тебе это. Но я для своих задач, тоже как то писал, простейший фильтр выделения границ, хочешь, глянь код (BCB 6++): При желании, могу на Дельфи привести.

Код:
Graphics::TBitmap*  Test = new Graphics::TBitmap;
 Test->LoadFromFile(opLeft->FileName);
 int i, j, sum_previos, sum_current;
 float k;
 k = StrToFloat(Edit1->Text);

 Byte *Line;
 for (i=0; i<Test->Height;i++ )
 {
  Line = (Byte *)Test->ScanLine;
  for (j=0; j<3*Test->Width-3; j=j+3)
  {
   sum_previos = Line[j  ] + Line[j+1] + Line[j+2];
   sum_current = Line[j+3] + Line[j+4] + Line[j+5];
   if ((sum_current<(1-k)*sum_previos)||
       (sum_current>(1+k)*sum_previos))
   {
    Line[j]=0; Line[j+1]=0; Line[j+2]=0;

   }
   else
   {
    Line[j]=255; Line[j+1]=255; Line[j+2]=255;
   }
  }
 }
 imLeft->Canvas->Draw(0,0, Test);
 Test->Free();


Принцип действия такой, сравниваем два соседних пикселя, если различаются больше чем установленная величина - граница, если меньше. то нет.
548
21 мая 2008 года
Maximillian_Cavalera
157 / / 16.08.2007
seska, спасибо. Я пробовал этот алгоритм при k = 0.0001 ... 5 - изображение больше похоже на испорченный телевизор.

А кто нидь может сказать алгоритм Кэнни, желательно с исходником.
33K
22 мая 2008 года
seska
26 / / 10.04.2008
Цитата:
seska, спасибо. Я пробовал этот алгоритм при k = 0.0001 ... 5 - изображение больше похоже на испорченный телевизор.


Все зависит от тех задач, которые нужно реализовать. Для меня даже такой способ подходил. Алгоритм Кенни искал в инете (реализацию), но к сожалению безрезультатно. Посмотри градиентный метод в ссылке, которую тебе дал, вроде не такой сложный в исполнении.
Тьфу блин, самое главное забыл!!! Эта штука (код, который я выложил) работает тока с 24 битным BMP...

 
Код:
Line[j]=0; Line[j+1]=0; Line[j+2]=0;

Тут же идет последовательный доступ к каждому байту, а такое возможно тока в модели BMP 24 бита.... Может поэтому испорченый телевизор был?
33K
22 мая 2008 года
seska
26 / / 10.04.2008
Еще есть книжка, про компьютерное зрение. Описаны различные алгоритмы работы с растровой графикой. Во многом разобраться вполне реально. Книжка Д.А. Форсайт, Ж. Понс - Компьютерное зрение. Современный подход. Если нужна, пиши мыло, скину (тут математика, ни о каком программировании в книжке не говорится).
548
22 мая 2008 года
Maximillian_Cavalera
157 / / 16.08.2007
seska, спасибо, однако мне время поджимает и разбираться особо некогда. Но книжку вышли пожалуйста. Моё мыло кавалера89@mail.ru (кавалера = cavalera)
А у тебя нету написанного алгоритма градиентного метода?
548
31 мая 2008 года
Maximillian_Cavalera
157 / / 16.08.2007
Вот попробовал реализовать с помощью OpenCV. У меня во время выполнения почему-то выдаёт ошибку, что-то с форматом цвета вроде, можете посмотреть код и сказать в чём дело
Код:
void TForm1::BubbleContours(Graphics::TBitmap &bmp, Graphics::TBitmap &outputBmp)
{
    IplImage *image = TBitmapToIplImage(&bmp);
    IplImage* laplace = 0;
    IplImage* colorlaplace = 0;
    IplImage* planes[3] = { 0, 0, 0 };
    // Laplacian
    if( !laplace )
    {
        for(int i = 0; i < 3; i++ )
        {
            planes = cvCreateImage( cvSize(image->width,image->height), 8, 1 );
        }
        laplace = cvCreateImage( cvSize(image->width,image->height), IPL_DEPTH_16S, 1 );
        colorlaplace = cvCreateImage( cvSize(image->width,image->height), 8, 3 );
     }
     cvCvtPixToPlane( image, planes[0], planes[1], planes[2], 0 );
     for(int i = 0; i < 3; i++ )
     {
        cvLaplace( planes, laplace, 3 );
        cvConvertScaleAbs( laplace, planes, 1, 0 );
     }
     cvCvtPlaneToPix( planes[0], planes[1], planes[2], 0, colorlaplace );
     colorlaplace->origin = image->origin;
     // Contours
     IplImage *edge = cvCreateImage( cvSize(image->width,image->height), IPL_DEPTH_8U, 3 );
     IplImage *convertedImage = cvCreateImage( cvSize(image->width,image->height), IPL_DEPTH_8U, 3 );
     cvCanny(convertedImage, edge, 50, 200, 3 );  //вот здесь выдаёт ошибку
     IplImageToTBitmap(edge, &outputBmp);
}


вот что получается при использовании лапласа(на картинке)
38K
06 июня 2008 года
morris_1
6 / / 06.06.2008
модель построить можно с помощью MATLAB, подробнее mathworks.com в прошлом я занемался что-то подобным, но к сожалению кода для построения модели, незнаю.
Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог