2015-11-11 2 views
-2

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

  1. Использование чистого OpenCV требует хранить Mat в .xml или .yml файл (How to write a Float Mat to a file in OpenCV: принят ответ)
  2. Найти координаты полигона, где Есть вершины и хранить только те координаты в базу данных

Ниже приводится образ образца мата, который я собираюсь хранить.

enter image description here

Первый вариант кажется возможным, но я не знаю, как реализовать второй подход. Если возможно, это было бы наиболее эффективно, как я думаю, потому что тогда для каждой статьи будет сохранено всего несколько координат. Я могу реализовать сложную процедуру, чтобы найти вершины для этого, а также перерисовать изображение Мата, используя эти координаты, когда это необходимо. Но я надеюсь, что для этой задачи есть простой процесс в opencv.

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

+0

Использование _findContours_ с параметром _method_ как CV_CHAIN_APPROX_SIMPLE. В документации сказано: ** _ CV_CHAIN_APPROX_SIMPLE сжимает горизонтальные, вертикальные и диагональные сегменты и оставляет только их конечные точки. Например, правый прямоугольный контур закодирован с 4 точками ._ ** – dhanushka

+0

Какой будет выход метода findContours здесь? Мне интересно с этим примером> http://docs.opencv.org/2.4/doc/tutorials/imgproc/shapedescriptors/find_contours/find_contours.html –

+0

_findContours_ с CV_CHAIN_APPROX_SIMPLE, скорее всего, выведет что-то похожее на то, что вы ожидаете в своем втором подходе , – dhanushka

ответ

1

Вы можете просто использовать findContours, с подходящим методом контурным приближением. В принципе, кроме CV_CHAIN_APPROX_NONE, который сохранит все точки, любой другой метод подходит для этого примера: CV_CHAIN_APPROX_SIMPLE, CV_CHAIN_APPROX_TC89_L1 и CV_CHAIN_APPROX_TC89_KCOS.

Вы можете сохранить эти пункты в своей базе данных. Затем вы можете перезагрузить эти очки и нарисовать исходное изображение с помощью fillPoly.

Этот простой пример показывает извлеченные точки контуров с помощью метода аппроксимации и как повторно рисовать изображение с этими точками.

Примечание что вы изображение псевдонимами (вы, вероятно, сохранили его в формате JPEG до PNG), так что вам нужно удалить ступенчатость, например сохранение только точки со значением равна 255.

#include <opencv2\opencv.hpp> 
#include <vector> 
using namespace std; 
using namespace cv; 

int main() 
{ 
    Mat1b img = imread("path_to_image", IMREAD_GRAYSCALE); 

    // Removing compression artifacts 
    img = img == 255; 

    vector<vector<Point>> contours; 
    findContours(img.clone(), contours, RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE); 

    if (contours.empty()) {return -1;} 

    // Save the vertices "contours[0]" 

    // Result image 
    Mat3b res; 
    cvtColor(img, res, COLOR_GRAY2BGR); 
    for (int i = 0; i < contours[0].size(); ++i) 
    { 
     circle(res, contours[0][i], 3, Scalar(0,255,0)); 
    } 

    // Reconstruct image from contours vertex 

    // Load the vertices 
    vector<vector<Point>> vertices = { contours[0] }; 

    Mat1b rec(img.rows, img.cols, uchar(0)); 
    fillPoly(rec, vertices, Scalar(255)); 

    imshow("Vertices", res); 
    imshow("Reconstructed", rec); 
    waitKey(); 

    return 0; 
} 

Green вершины с методом контурной аппроксимации:

enter image description here

+0

Привет Мики .. :-) Большое спасибо за ответ. Я отвечу с результатами. Кстати, есть ли возможность пропустить какие-либо вершины или немного сдвинуть их координаты, обнаружив их или восстановив изображение назад? –

+0

@SamithaChathuranga no, vertices и _reconstructed_ matrix будут согласованными. Не забудьте сохранить исходные изображения в png (или любом другом формате без потерь), чтобы избежать артефактов сжатия, удаление которых изменит исходную форму и даст вам неточные вершины. – Miki

+0

Хорошо, да, я сохраняю изображения в формате .png (он был преобразован в jpg только для загрузки на вопрос) –

1

Чувствительный подход ... вы можете с легкостью сохранить Mat как изображение в OpenCV - желательно PGM или PNG, так как они без потерь. Затем вы можете передать изображение в программу вектор-трассировщика, например potrace, и получить ее, чтобы сообщить вам схему в формате SVG и сохранить ее в своей базе данных.

Так, potrace любит PGM файлы, так что вы либо сохранить схему как PGM в OpenCV или как PNG, то вы используете ImageMagick, чтобы сделать это в PGM и передать его potrace так:

convert OpenCVImage.png pgm:- | potrace - -b svg -o file.svg 

который получит вам svg файл вроде этого:

<?xml version="1.0" standalone="no"?> 
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN" 
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"> 
<svg version="1.0" xmlns="http://www.w3.org/2000/svg" 
width="3486.000000pt" height="4747.000000pt" viewBox="0 0 3486.000000 4747.000000" 
preserveAspectRatio="xMidYMid meet"> 
<metadata> 
Created by potrace 1.13, written by Peter Selinger 2001-2015 
</metadata> 
<g transform="translate(0.000000,4747.000000) scale(0.100000,-0.100000)" 
fill="#000000" stroke="none"> 
<path d="M0 23735 l0 -23735 17430 0 17430 0 0 23735 0 23735 -17430 0 -17430 
0 0 -23735z m20980 6560 l0 -3415 -399 0 c-293 0 -402 3 -407 12 -7 11 -68 11 
-2391 -9 l-781 -6 -6 -6576 c-3 -3617 -9 -6840 -12 -7163 l-6 -588 -1939 0 
-1939 0 0 10580 0 10580 3940 0 3940 0 0 -3415z"/> 
</g> 
</svg> 

Вы можете просмотреть, что в веб-браузере, кстати.

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

convert outline.svg outline.png 

Я хотел бы отметить, что вся ваша PNG на самом деле только 32kB и хранилище довольно дешево, поэтому вряд ли стоит сэкономить время для создания векторизованного изображения для экономии места. На самом деле, если вы используете достойный инструмент, например ImageMagick, и конвертируете свое изображение в одноразрядный PNG, оно сводится к 6 150 байтам, что довольно мало ...

convert YourBigInefficientOutline.png NiceImageMagickOutlineOf6kB.png 

И, если вы можете справиться уменьшая контур в размере до 1/5 его оригинала, который будет по-прежнему, вероятно, будет достаточно, чтобы найти газетную статью, вы могли бы сделать:

convert YourBig.png -resize 700x900 MySmall.png 

который весит всего 1,825 байт.

+1

Кстати, встроенный детектор Harris Corner Detector в OpenCV отлично справляется с поиском углов ... https://github.com/Itseez/opencv/blob/master/samples/cpp/tutorial_code/TrackingMotion/cornerHarris_Demo .cpp И вы могли бы воссоздать схему, используя * «Алгоритм обертывания подарков» * здесь ... https://en.wikipedia.org/wiki/Gift_wrapping_algorithm –

+0

Я попробую. Thanx. Кстати, процесс в вашем ответе интересен. Но кажется, что это делает вещи более сложными, поскольку хранение оригинальных изображений .png кажется дешевым. Особое использование других инструментов усложняет задачу –

1
cv::Mat inputImage = cv::imread("input.png", CV_LOAD_IMAGE_GRAYSCALE); 

// find non-zero point coordinates 
cv::Mat nonZeroCoordinates; 
cv::findNonZero(inputImage, nonZeroCoordinates); 

Затем вы можете сохранить матрицу nonZeroCoordinates в свой файл для использования.

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

std::vector<std::vector<cv::Point> > points; 
points.push_back(nonZeroCoordinates); 

cv::Mat output = cv::Mat::zeros(inputImage.size(), CV_8UC1); 
cv::fillPoly(output, points, cv::Scalar(255)); 

Надеется, что это помогает!

+0

Как я вижу, это не сильно отличается от сохранения исходного объекта Mat. Здесь u создает новый объект Mat nonZeroCoordinates для представления исходного (это может потреблять меньше места), а затем использовать его для воспроизведения оригинального Mat. Я хочу сохранить данные в файле. –

+0

Какие детали вы ищите? – Derman

+0

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

1

Это зависит от того, насколько универсальными могут быть полигоны. Если края многоугольника всегда параллельны осям x и y, тогда вы можете посмотреть на пиксели в 8-пиксельной части определенного пикселя, и если есть нечетное число белых пикселей, то вы найдете угол. Или используйте 4-окрестности и проверьте четное количество белых пикселей.

+0

Спасибо за ценный намек. Но я надеюсь, что, если это будет возможно, opencv-специфический подход. –