Преобразование изображения BMP в набор инструкций для плоттера?

У меня есть такой плоттер:  Устройство PloterXY.

Задача, которую мне предстоит реализовать, - это преобразование 24-битного BMP в набор инструкций для этого плоттера. В плоттере я могу изменить 16 распространенных цветов. Первая сложность, с которой я сталкиваюсь, - это редукция цветов. Вторая сложность, с которой я сталкиваюсь, заключается в том, как преобразовать пиксели в набор инструкций по рисованию.

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

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

Некоторые начальные результаты:

Цветок 1 - уменьшение количества цветов.

Цветок 2 - уменьшение количества цветов.

Цветок 3 - уменьшение количества цветов.


person Todor Balabanov    schedule 17.04.2016    source источник
comment
Google вам точно поможет. stackoverflow.com/questions/622573/ Для преобразования в ваш плоттер это будет сильно зависеть от того, какие изображения у вас есть. Вы бы векторизовали персонажа иначе, чем цветок   -  person Piglet    schedule 17.04.2016
comment
вам не нужно терять цвета, используйте дизеринг ... Векторизация зависит от того, что вы хотите ... только контуры или полное заполнение ... также это очень сильно зависит от содержимого изображения rel life photo if другое, чем мультипликационный эскиз ... если вы не ограничены растровым изображением, вы также можете напрямую использовать 2D векторные форматы, такие как svg, wmf, emf, dwg, ... добавить пример изображения   -  person Spektre    schedule 17.04.2016
comment
Я буду использовать реальные фотоизображения. Я думаю о каком-то способе лучшего уменьшения количества цветов, чем стандартные алгоритмы. Например, в GIMP очень хорошо реализован модуль уменьшения цветов, но это сокращение общего назначения. Мне нужно будет выполнить векторизацию изображений, и мне интересно, есть ли способы добиться лучшего уменьшения цветов, связанных со спецификой моей задачи.   -  person Todor Balabanov    schedule 18.04.2016
comment
Для начала вы должны объяснить, какие есть доступные инструкции по рисованию ...   -  person fjardon    schedule 18.04.2016
comment
Я предполагаю, что время / стоимость изменения цвета относительно времени, необходимого для перемещения головки плоттера, также является определяющим фактором в том, как вы должны печатать, поэтому вам нужно будет идентифицировать плоттер и его руководство пользователя.   -  person Mark Setchell    schedule 22.04.2016
comment
какие цвета у вас есть и можно ли их комбинировать (если вы рисуете больше цветов в одной и той же области, они объединяются вместе (адитивный (RGB) / субстративный (CMY))? или последний использованный (самый верхний) перезапишет предыдущий? требуется сглаживание много точек, которые могут значительно сократить срок службы плоттера и увеличить время рендеринга. Количество цветов постоянное (нет ШИМ-клапанов, которые просто центроприводятся)?   -  person Spektre    schedule 23.04.2016
comment
Марк Сетчелл, спасибо за комментарий. Это плоттер: makeblock.cc/xy-plotter-robot-kit Это относительно медленное устройство. У меня будет 16 общих цветов: gchart.googlecode.com/svn/trunk/doc/com/googlecode/gchart/ Смена цветов будет очень медленным процессом, потому что масляной краске нужно время, чтобы высохнуть. Spektre, спасибо за комментарий. Я могу нарисовать один цвет поверх другого.   -  person Todor Balabanov    schedule 27.04.2016


Ответы (1)


Дитеринг

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

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

  1. сбросить цветовой аккумулятор до нуля
  2. process all pixels
    1. for each pixel add its color to accumulator
    2. найти наиболее близкое соответствие результата в вашей палитре
    3. визуализировать выбранный цвет палитры
    4. вычесть выбранный цвет палитры из аккумулятора

Вот ваше входное изображение (я их собрал):

input

Вот изображение результата для вашего источника:

результат

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

Вот код (C ++), который я делаю с помощью:

picture pic0,pic1,pic2;
    // pic0 - source img
    // pic1 - source pal
    // pic2 - output img
int x,y,i,j,d,d0,e;
int r,g,b,r0,g0,b0;
color c;
List<color> pal;
// resize output to source image size clear with black
pic2=pic0; pic2.clear(0);
// create distinct colors pal[] list from palette image
for (y=0;y<pic1.ys;y++)
 for (x=0;x<pic1.xs;x++)
    {
    c=pic1.p[y][x];
    for (i=0;i<pal.num;i++) if (pal[i].dd==c.dd) { i=-1; break; }
    if (i>=0) pal.add(c);
    }
// dithering
r0=0; g0=0; b0=0;   // no leftovers
for (y=0;y<pic0.ys;y++)
 for (x=0;x<pic0.xs;x++)
    {
    // get source pixel color
    c=pic0.p[y][x];
    // add to leftovers
    r0+=WORD(c.db[picture::_r]);
    g0+=WORD(c.db[picture::_g]);
    b0+=WORD(c.db[picture::_b]);
    // find closest color from pal[]
    for (i=0,j=-1;i<pal.num;i++)
        {
        c=pal[i];
        r=WORD(c.db[picture::_r]);
        g=WORD(c.db[picture::_g]);
        b=WORD(c.db[picture::_b]);
        e=(r-r0); e*=e; d =e;
        e=(g-g0); e*=e; d+=e;
        e=(b-b0); e*=e; d+=e;
        if ((j<0)||(d0>d)) { d0=d; j=i; }
        }
    // get selected palette color
    c=pal[j];
    // sub from leftovers
    r0-=WORD(c.db[picture::_r]);
    g0-=WORD(c.db[picture::_g]);
    b0-=WORD(c.db[picture::_b]);
    // copy to destination image
    pic2.p[y][x]=c;
    }
// render found palette pal[] (visual check/debug)
x=0; y=0; r=16; g=pic2.xs/r; if (g>pal.num) g=pal.num;
for (y=0;y<r;y++)
 for (i=0;i<g;i++)
  for (c=pal[i],x=0;x<r;x++)
   pic2.p[y][x+(i*r)]=c;

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

  • xs,ys разрешение
  • color p[ys][xs] прямой доступ к пикселям (32-битный формат пикселей, 8 бит на канал)
  • clear(DWORD c) заливка изображения цветом c

color - это просто union из DWORD dd и BYTE db[4] для простого доступа к каналу.

List<> - это мой шаблон (динамический массив / список>

  • List<int> a совпадает с int a[].
  • add(b) добавить к нему букву b в конце списка
  • num - количество элементов в списке

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

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

person Spektre    schedule 24.04.2016
comment
@MarkSetchell Если вам это понравилось, взгляните также на масштабируемое дизеринг. Только что загрузил туда новый анимированный GIF. - person Spektre; 26.04.2016
comment
Spektre, большое спасибо, потрясающе хороший ответ. Я специально не предоставил слишком много информации об иницииле. Я хотел добиться чего-то вроде мозгового штурма, чтобы собрать новые идеи. Здесь вы можете увидеть более подробную информацию о том, как я решал проблему до сих пор: github.com/TodorBalabanov/EllipsesImageApproximator < / а> - person Todor Balabanov; 27.04.2016
comment
Хороший алгоритм. Мне это нравится. У него есть некоторые недостатки (например, создание волн), но он действительно прост и позволяет довольно быстро выполнять. - person Raffzahn; 10.01.2019
comment
@Spektre Конечно, опять же, любая дополнительная фильтрация не только улучшит изображение, но и приведет к резкому снижению производительности из-за более сложных выборок данных и вычислений. Это действительно, как указано выше, поскольку это может быть реализовано в нескольких строках сборки - возможно, меньше, чем код C выше :)) Для меня это большое достижение. - person Raffzahn; 10.01.2019
comment
@Raffzahn да, особенно используя инструкции SSE / SIMD, такие как насыщенное сложение ... одновременное выполнение всех цветовых каналов по одной инструкции :) - person Spektre; 10.01.2019
comment
@Spektre Naa, а не навороченные штуки, настоящая сборка, например, 6502 или 8086. Подгонка таких к современным процессорам, которые специально созданы для этого, - обман :)) - person Raffzahn; 10.01.2019
comment
@Raffzahn :) ... Я помню дни Z80 кодирования и перевода на бумаге, а затем тыкать в RAM и рандомизировать usr :) ... и часы поиска ошибки в нем - person Spektre; 10.01.2019