Как сделать это преобразование изображения?

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

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

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

Может ли кто-нибудь указать мне на простое преобразование / процедуру, которая может это сделать? Предпочтительно, что-то я могу легко найти для примера кода.

Я чувствовал себя как кодирование на C ++ для вас, а не с помощью командной строки, как и для моего другого ответа, поэтому я поставил его в качестве другого ответа. Кроме того, он также реализует алгоритм Дугласа-Пьюкера и, для удовольствия и хорошей меры, оживляет его.

//////////////////////////////////////////////////////////////////////////////// // main.cpp // Mark Setchell // To find a blob in an image and generate line segments that describe it, // Use ImageMagick Magick++ and Ramer-Douglas-Peucker algorithm. // https://en.wikipedia.org/wiki/Ramer-Douglas-Peucker-algorithm // // function DouglasPeucker(PointList[], epsilon) // // Find the point with the maximum distance // dmax = 0 // index = 0 // end = length(PointList) // for i = 2 to ( end - 1) { // d = perpendicularDistance(PointList[i], Line(PointList[1], PointList[end])) // if ( d > dmax ) { // index = i // dmax = d // } // } // // If max distance is greater than epsilon, recursively simplify // if ( dmax > epsilon ) { // // Recursive call // recResults1[] = DouglasPeucker(PointList[1...index], epsilon) // recResults2[] = DouglasPeucker(PointList[index...end], epsilon) // // Build the result list // ResultList[] = {recResults1[1...length(recResults1)-1], recResults2[1...length(recResults2)]} // } else { // ResultList[] = {PointList[1], PointList[end]} // } // // Return the result // return ResultList[] // end // //////////////////////////////////////////////////////////////////////////////// #include  #include  #include  #include  #include  #include  #include  #include  #include  #include  using namespace std; using namespace Magick; // Global debug image Image DEBUG_IMAGE; int DEBUG_NUM=0; char DEBUG_NAME[64]; #define DEBUG(img) {sprintf(DEBUG_NAME,"debug-%04d.png",DEBUG_NUM++);img.write(DEBUG_NAME);} // Point class class Point { private: double px,py; public: // Constructor Point(double x = 0.0, double y = 0.0) { px = x; py = y; } // Getters double x() { return px; } double y() { return py; } }; // Line class class Line { private: Point start,end; public: // Constructor Line(Point a=Point(0,0), Point b=Point(0,0)){ start=a; end=b; } // Getters double startx() { return start.x(); } double starty() { return start.y(); } double endx() { return end.x(); } double endy() { return end.y(); } double DistanceTo(Point p){ double y2my1 = end.y() - start.y(); double x2mx1 = end.x() - start.x(); double numerator = fabs(y2my1*px() - x2mx1*py() + end.x()*start.y() - end.y()*start.x()); double denominator = sqrt(y2my1*y2my1 + x2mx1*x2mx1); return numerator/denominator; } }; void DouglasPeucker(vector& PointList,int startindex,int endindex,double epsilon,vector& Results){ // Find the point with the maximum distance double d,dmax=0; int i,index; Line line(PointList[startindex],PointList[endindex]); for(i=startindex+1;idmax){ index=i; dmax=d; } } // If max distance is greater than epsilon, recursively simplify if ( dmax > epsilon ) { // Recursive call to do left and then right parts DouglasPeucker(PointList,startindex,index,epsilon,Results); DouglasPeucker(PointList,index,endindex,epsilon,Results); } else { Results.push_back(line); // Rest of else statement is just generating debug image std::list drawList; drawList.push_back(DrawableStrokeColor("blue")); drawList.push_back(DrawableStrokeWidth(1)); drawList.push_back(DrawableLine(line.startx(),line.starty(),line.endx(),line.endy())); DEBUG_IMAGE.draw(drawList); DEBUG(DEBUG_IMAGE); } } int main(int argc,char **argv) { InitializeMagick(*argv); // Create some colours Color black = Color("rgb(0,0,0)"); Color white = Color("rgb(65535,65535,65535)"); Color red = Color("rgb(65535,0,0)"); Color green = Color("rgb(0,65535,0)"); Color blue = Color("rgb(0,0,65535)"); // Create a fuzz factor scaling assert(QuantumRange==65535); const double fuzzscale = QuantumRange/100; // Load wave image Image image("wave.jpg"); int w = image.columns(); int h = image.rows(); cout << "Dimensions: " << w << "x" << h << endl; // Copy for debug purposes DEBUG_IMAGE=image; // Fill top-left greyish area of image with green image.colorFuzz(50*fuzzscale); image.opaque(white,green); DEBUG(image); // Fill bottom-right blackish area of image with blue image.colorFuzz(20*fuzzscale); image.opaque(black,blue); DEBUG(image); // Fill rest of image with red image.colorFuzz(81*fuzzscale); image.opaque(red,red); DEBUG(image); // Median filter to remove jaggies image.medianFilter(25); DEBUG(image); // Find red-green edge by cloning, making blue red, then looking for edges std::vector RGline; Image RGimage=image; RGimage.opaque(blue,red); DEBUG(RGimage); RGimage.type(GrayscaleType); DEBUG(RGimage); RGimage.normalize(); DEBUG(RGimage); RGimage.edge(1); DEBUG(RGimage); // Now pass over the image collecting white pixels (from red-green edge) // Ignore a single row at top & bottom and a single column at left & right edges // Get a "pixel cache" for the entire image PixelPacket *pixels = RGimage.getPixels(0, 0, w, h); int x,y; for(x=1; x Results; // epsilon = Max allowable deviation from straight line in pixels // Make epsilon smaller for more, shorter, more accurate lines // Make epsilon larger for fewer, more approximate lines double epsilon=18; DouglasPeucker(RGline,0,RGline.size()-1,epsilon,Results); int lines1=Results.size(); cout << "Upper boundary mapped to " << lines1 << " line segments (epsilon=" << epsilon << ")" << endl; // Find red-blue edge by cloning, making green red, then looking for edges std::vector RBline; Image RBimage=image; RBimage.opaque(green,red); DEBUG(RBimage); RBimage.type(GrayscaleType); DEBUG(RBimage); RBimage.normalize(); DEBUG(RBimage); RBimage.edge(1); DEBUG(RBimage); // Now pass over the image collecting white pixels (from red-green edge) // Ignore a single row at top & bottom and a single column at left & right edges // Get a "pixel cache" for the entire image pixels = RBimage.getPixels(0, 0, w, h); for(x=1; x 

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

Мой Makefile выглядит так:

 main: main.cpp clang++ -std=gnu++11 -Wall -pedantic main.cpp -o main $$(Magick++-config --cppflags --cxxflags --ldflags --libs) 

Не совсем полный ответ, но, возможно, достаточно, чтобы вы начали или достаточно, чтобы кто-то еще прокомментировал и добавил еще несколько идей, – и никто не сказал, что ответы должны были быть завершены в любом случае.

Я использовал ImageMagick только из командной строки, чтобы сегментировать изображение в три раза – размытый серо-красный немного больно, если вы попытаетесь сделать простое уменьшение цвета до трех цветов. ImageMagick установлен на большинстве дистрибутивов Linux и доступен для OSX и Windows.

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

 convert wave.jpg \ -fuzz 50% -fill "rgb(255,255,0)" -opaque white \ -fuzz 20% -fill "rgb(250,250,0)" -opaque black \ -fuzz 10% -fill red +opaque yellow result.png 

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

Теперь я могу изменить два временных оттенка желтого обратно на белый и черный:

 convert result.png -fuzz 0 \ -fill white -opaque "rgb(255,255,0)" \ -fill black -opaque "rgb(250,250,0)" result2.png 

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

И тогда я могу сгладить jaggies с помощью медианного фильтра:

 convert result2.png -median 25x25 result3.png 

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

Теперь я могу обнаружить грани, используя -edge :

 convert result3.png -edge 1 result4.png 

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

Теперь вы видите, как это работает, вы можете сделать все это в одной простой команде:

 convert wave.jpg \ -fuzz 50% -fill "rgb(255,255,0)" -opaque white \ -fuzz 20% -fill "rgb(250,250,0)" -opaque black \ -fuzz 10% -fill red +opaque yellow \ -fuzz 0 -fill white -opaque "rgb(255,255,0)" \ -fill black -opaque "rgb(250,250,0)" -median 25x25 -edge 1 result.png 

Теперь вы можете найти все точки, в которых красный пиксель касается белого пикселя – я бы предположил, что вы делаете это в Magick ++ (привязка к C ++ для ImageMagick – хотя есть и Ruby и Python и привязки PHP, если вы предпочитаете), и помещайте эти точки в список STL и применить алгоритм Ramer-Douglas-Peucker для получения сегментов линии.

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

  • Как преобразовать строку в float?
  • c ++ конвертировать из LPCTSTR в const char *
  • Interesting Posts

    Обратный атрибут в NHibernate

    «ImportError: без модуля с именем _ssl» с dev_appserver.py из Google App Engine

    Как сделать снимок экрана с помощью xlib?

    ОШИБКА: разрешение отклонено для отношения tablename на Postgres при попытке SELECT как пользователя, использующего только для чтения

    Каков наилучший способ заставить TFS выводить каждый проект в свой собственный каталог?

    Как узнать, содержит ли массив строку

    Как разбить вектор на группы регулярных последовательных последовательностей?

    Как настроить цвет каталога 'ls' в разделе zsh

    Как управлять исключениями, сброшенными фильтрами весной?

    Matlab ode solvers: изменение состояния и заданное время

    В чем причина шумов помех в динамиках ПК и как я могу избавиться от них?

    Инициализация массива C ++

    Создание FLV-видео с альфа-каналом с использованием инструментов с открытым исходным кодом

    Как обеспечить запуск только одного экземпляра моего приложения?

    Как определить, открыт ли порт на сервере Windows?

    Давайте будем гением компьютера.