Обнаружение разрушения в руке с использованием обработки изображения

Что я сделал :

  1. Взять входное изображение и изменить размер изображения до стандартного размера

    как я должен сравнить это с шаблоном.

  2. преобразуется в двоичную форму с использованием порогового значения.

  3. Обнаружен подключенный компонент и отображен самый большой компонент.

    Как показывает весь hand.as здесь:

    IMG

  4. Поместите изображение в те же координаты, чтобы проверить расположение пальца для сравнения с изображением

    но их расположение отличается фиолетовым, это шаблон изображения

    IMG

  5. Я делаю сравнение изображения с методом вычитания изображения.

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

Есть ли другой способ сделать это? Дайте мне знать, если их есть.

Вот оригинальные необработанные изображения:

введите описание изображения здесь
введите описание изображения здесь

4

Решение

Вы почти поняли, но то, что я имел в виду (из комментариев), было больше похоже на это:

  1. подготовить образ

    переключиться на оттенки серого, устранить шум (путем некоторого размытия), расширить динамический диапазон и т. д.

  2. получить изображение обоими x,y оси и создать градиентное 2D-поле

    поэтому перекрасим изображение и создадим 2D векторное поле. каждый пиксель имеет RGB, поэтому используйте R для одной оси и B для другой. Я делаю это так:

    Blue(x,y)=abs(Intensity(x,y)-Intensity(x-1,y))
    Red (x,y)=abs(Intensity(x,y)-Intensity(x,y-1))
    

    Результат подстановки выглядит так: края

  3. Пороговое изображение, чтобы подчеркнуть края

    Так что выбирайте каждый пиксель и сравнивайте Blue(x,y)+Red(x,y)<treshold если правда перекрасить в неизвестный еще перекрасить в край цвет. Для вашего примера изображения я использовал порог 24 После этого сгладьте результат, чтобы заполнить небольшие пробелы размытым цветом. Результат подстановки выглядит так: введите описание изображения здесь

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

  4. определить фон

    Так что теперь, чтобы отличить фон от костей внутри, я использую специальный метод заполнения (но подойдёт простая заливка), который я разработал для DIP вещи и нашли очень полезными много раз над прежними ожиданиями.

    void growfill(DWORD c0,DWORD c1,DWORD c2); // grow/flood fill c0 neigbouring c1 with c2
    

    Который просто проверяет все пиксели на изображении и, если найден цвет c0 возле c1 затем перекрашивает его c2 и петли, пока не произошло перекрашивание. Для большего разрешения обычно намного быстрее, чем для заливки из-за отсутствия необходимости в рекурсии или в стеке / куче / списках. Также его можно использовать для многих интересных эффектов, таких как прореживание / утолщение и т. Д. С помощью нескольких простых вызовов.

    ОК, вернуться к теме, я выбираю 3 основных цвета:

                                 //RRGGBB
    const DWORD col_unknown   =0x00408020;  // yet undetermined pixels
    const DWORD col_background=0x00000000;
    const DWORD col_edge      =0x00FFFFFF;
    

    Теперь фон точно по краям, поэтому я рисую прямоугольник с col_background вокруг изображения, и рост заполняет все col_unknown пикселей рядом col_background с col_background который в основном заливает изображение снаружи внутрь.

    После этого я перекрашиваю все пиксели, которые не принадлежат ни к одному из трех определенных цветов, в их наиболее близкое соответствие. Это удалит размытие, так как оно больше не желательно. Результат подстановки выглядит так: фон

  5. Сегментация / маркировка

    Теперь просто отсканируйте все изображение и, если есть col_unknown найден рост, заполните его отличным цветом / индексом объекта. Измените конкретный цвет объекта / индекс (приращение) и продолжайте до конца изображения. Остерегайтесь цветов, которые вы должны избегать использования трех предопределенных цветов, иначе вы объедините области, которые вам не нужны.

    Конечный результат выглядит так: скелет

  6. Теперь вы можете применять любую форму анализа / сравнения

    у вас есть пиксельная маска каждой области объекта, чтобы вы могли подсчитать пиксели (область) и удалить игнорируемые слишком маленькие области. Вычислите среднюю позицию пикселя (в центре) каждого объекта и используйте его, чтобы определить, какая это кость на самом деле. Вычислить однородность площади … масштабировать до шаблонных костей … и т.д …

Вот код C ++, с которым я это сделал

color c,d;
int x,y,i,i0,i1;
int tr0=Form1->sb_treshold0->Position;  // =24 treshold from scrollbar
//RRGGBB
const DWORD col_unknown   =0x00408020;  // yet undetermined pixels
const DWORD col_background=0x00000000;
const DWORD col_edge      =0x00FFFFFF;
// [prepare image]
pic1=pic0;                  // copy input image pic0 to output pic1
pic1.pixel_format(_pf_u);   // convert to grayscale intensity <0,765>
pic1.enhance_range();       // recompute colors so they cover full dynamic range
pic1.smooth(1);             // blur a bit to remove noise
// extract edges
pic1.deriveaxy();           // compute derivations (change in intensity in x and y axis as 2D gradient vector)
pic1.save("out0.png");
pic1.pf=_pf_rgba;           // from now on the recolored image will be RGBA (no need for conversion)
for (y=0;y<pic1.ys;y++)     // treshold recolor
for (x=0;x<pic1.xs;x++)
{
c=pic1.p[y][x];
i=c.dw[picture::_x]+c.dw[picture::_y];              // i=|dcolor/dx| + |dcolor/dy|
if (i<tr0) c.dd=col_unknown; else c.dd=col_edge;    // treshold test&recolor
pic1.p[y][x]=c;
}
pic1.smooth(5);             // blur a bit to fill the small gaps
pic1.save("out1.png");

// [background]
// render backround color rectangle around image
pic1.bmp->Canvas->Pen->Color=rgb2bgr(col_background);
pic1.bmp->Canvas->Brush->Style=bsClear;
pic1.bmp->Canvas->Rectangle(0,0,pic1.xs,pic1.ys);
pic1.bmp->Canvas->Brush->Style=bsSolid;
// growth fill all col_unknonw pixels near col_background pixels with col_background similar to floodfill but without recursion and more usable.
pic1.growfill(col_unknown,col_background,col_background);
// recolor blured colors back to their closest match
for (y=0;y<pic1.ys;y++)
for (x=0;x<pic1.xs;x++)
{
c=pic1.p[y][x];
d.dd=col_edge      ; i=abs(c.db[0]-d.db[0])+abs(c.db[1]-d.db[1])+abs(c.db[2]-d.db[2]);             i0=i; i1=col_edge;
d.dd=col_unknown   ; i=abs(c.db[0]-d.db[0])+abs(c.db[1]-d.db[1])+abs(c.db[2]-d.db[2]); if (i0>i) { i0=i; i1=d.dd; }
d.dd=col_background; i=abs(c.db[0]-d.db[0])+abs(c.db[1]-d.db[1])+abs(c.db[2]-d.db[2]); if (i0>i) { i0=i; i1=d.dd; }
pic1.p[y][x].dd=i1;
}
pic1.save("out2.png");

// [segmentation/labeling]
i=0x00202020; // labeling color/idx
for (y=0;y<pic1.ys;y++)
for (x=0;x<pic1.xs;x++)
if (pic1.p[y][x].dd==col_unknown)
{
pic1.p[y][x].dd=i;
pic1.growfill(col_unknown,i,i);
i+=0x00050340;
}
pic1.save("out3.png");

Я использую свой собственный класс изображений для изображений, поэтому некоторые участники:

  • xs,ys размер изображения в пикселях
  • p[y][x].dd это пиксель в (x,y) позиция как 32-битный целочисленный тип
  • p[y][x].dw[2] это пиксель в (x,y) позиционировать как целочисленный тип 2×16 бит для 2D поля
  • p[y][x].db[4] это пиксель в (x,y) позиционировать как целочисленный тип 4×8 бит для легкого доступа к каналу
  • clear(color) — очищает все изображение
  • resize(xs,ys) — изменяет размер изображения до нового разрешения
  • bmpVCL инкапсулированный GDI Растровое изображение с доступом к холсту
  • smooth(n) — быстрое размытие изображения n раз
  • growfill(DWORD c0,DWORD c1,DWORD c2) — расти / заливать c0 neigbouring c1 с c2

[Edit1] сканирование линии на основе обнаружения кости

Как и в связанном QA поиска горизонта, вы должны навести линии сканирования и найти отличительный признак, распознающий кость. Я бы начал с частичного вывода изображения (по оси X), как этот:

линия сканирования

Слева находится вывод интенсивности цвета по x (серый означает ноль), а справа исходное изображение. Боковые графы — это графы деривации как функция x а также y берется за строку и строку фактической позиции мыши. Как вы можете видеть, каждая кость имеет определенную форму в деривации, которую можно обнаружить. Я использовал очень простой детектор, как это:

  1. для обработанной строки изображения сделайте частичный вывод x
  2. найти все вершины (круги)
  3. удалить слишком маленькие пики и объединить пики одного знака вместе
  4. обнаружить кость по 4 последовательным пикам:
    1. большой минус
    2. маленький позитив
    3. маленький минус
    4. большой позитив

Для каждого найденного края кости я рисую красный и синий пиксели в исходном изображении (вместо больших пиков), чтобы визуально проверить правильность. Вы можете сделать это также по оси Y и объединить результаты. Чтобы улучшить это, вы должны использовать лучшее обнаружение, например, с помощью корреляции …

Вместо рендеринга края Вы можете легко создать маску костей, а затем сегментировать ее, чтобы разделить кости и обрабатывать, как в приведенном выше тексте. Также вы можете использовать морфологические операции, чтобы заполнить любые пробелы.

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

3

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]