Jump to content
Compvision.ru
barsukov

Emgu cv. Преобразование Хафа, выделение прямоугольника

Recommended Posts

Здравствуйте, форумчане! Прошу помочь с такой задачей- из данного изображения выделить только номер, т.е только эту самую белую область с буквами smile.png
Вот что у меня получилось: сделал программку на C#, она ищет на изображении номер автомобиля через каскад Хаара и выдаёт его в окне.

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

Взяв из примеров EmguCV(ShapeDetection) код для линий Хафа и прямоугольников я подставил его в свою программу, но столкнулся с такими проблемами:

1) в случае линий - их слишком много, а прямоугольники оно находит только идеально прямые;

2) на некоторых, казалось бы, хороших изображениях даже линии определяются неверно.

post-7270-0-62146100-1428436315_thumb.jppost-7270-0-92109400-1428436316_thumb.jp

Перед передачей изображения для нахождения линий Хафа его можно подвергнуть операции бинаризации. Некоторая проблема для меня в том, что после бинаризации линий находит куда больше(изображение 2, с ВАЗ 2112) чем без бинаризации(изображение 1, Лада Гранта), с параметрами cvAdaptiveThreshold игрался, но результата так и не получил. Т.е линий все равно много и я не пойму как оставить такие, по которым можно было бы обрезать изображение.

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

В прикреплениях есть код формы. Выглядит, думаю, плохо, но пока только такой есть smile.png

upd1. Добавочка. Hайти в конченом счете нужно буквы и цифры номера. Нашел в литературе употребление функции findContours для таких целей, скоро попробую.

Form1csTXT.zip

Edited by barsukov

Share this post


Link to post
Share on other sites

1 Поиск прямоугольника сработает только в идеальных условиях при которых сработает и findContours, но второй на МНОГО быстрее и мене "капризный"

2 Можно попробовать искать линии и  искать среди них композицию которая бы составляла прямоугольник.

Может поделитесь каскадом Хаара?

  • Like 1

Share this post


Link to post
Share on other sites

Может поделитесь каскадом Хаара?

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

 

P.S. Простой анализ логов git'а и пользователей Хабра показал, что их каскад называется haarcascade_russian_plate_number.xml, сделан пользователем ZlodeiBaal.

PP.S. Ну и в последнем посте есть ссылка на базу, на которой производилось обучение. Можно всё сделать самим.

Share this post


Link to post
Share on other sites

1 Поиск прямоугольника сработает только в идеальных условиях при которых сработает и findContours, но второй на МНОГО быстрее и мене "капризный"

2 Можно попробовать искать линии и  искать среди них композицию которая бы составляла прямоугольник.

Может поделитесь каскадом Хаара?

Спасибо, сегодня попробую. Nuzhny всё верно написал, используется тот самый haarcascade_russian_plate_number.xml.

Share this post


Link to post
Share on other sites

Почитал MateringOpenCV, решил применить оттуда извлечение прямоугольника(номера) с помощью RotatedRect. Пробую перейти с 2.4 на 3.0 версию EmguCV.

Share this post


Link to post
Share on other sites

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

 

post-7270-0-93914400-1429032513_thumb.jp

Share this post


Link to post
Share on other sites

Тебе  надо для найденных линий определить, какие из них будут границами прямоугольника.

На первый взгляд, это можно сделать простым перебором:

1. разделитьвсе линии на 4 группы: вертикальные слева от центра, вертикальные справа от центра, горизонтальные выше центра и горизонтальные ниже центра;

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

3. в качестве критерия правильности нахождения прямоугольника можно использовать два критерия:

3.1. пропорции прямоугольника должны минимально отличаться от пропорций идеального номера;

3.2. строить гистограмму яркости внутри прямоугольника и области снаружи его: гистограммы должны максимально отличаться.

 

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

Share this post


Link to post
Share on other sites

3.2

 

Тебе  надо для найденных линий определить, какие из них будут границами прямоугольника.

На первый взгляд, это можно сделать простым перебором:

1. разделитьвсе линии на 4 группы: вертикальные слева от центра, вертикальные справа от центра, горизонтальные выше центра и горизонтальные ниже центра;

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

3. в качестве критерия правильности нахождения прямоугольника можно использовать два критерия:

3.1. пропорции прямоугольника должны минимально отличаться от пропорций идеального номера;

3.2. строить гистограмму яркости внутри прямоугольника и области снаружи его: гистограммы должны максимально отличаться.

 

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

3.2 часто бывают машины с номером на фальшрешетке радиатора и  гистограмму яркости будет  такая-же как и у номера.

Share this post


Link to post
Share on other sites

Здравствуйте, форумчане! Прошу помочь с такой задачей- из данного изображения выделить только номер, т.е только эту самую белую область с буквами smile.png

 

upd1. Добавочка. Hайти в конченом счете нужно буквы и цифры номера. Нашел в литературе употребление функции findContours для таких целей, скоро попробую.

 

 

Искомые линии, ограничивающие номер, удовлетворяют следующим условиям:

  • примерно параллельны сторонам прямоугольника, проходят ближе к его границам, чем к центру(надо уточнить)
  • проходят вдоль выраженного края(в смысле того, который обнаруживается edge-детектором)
  • их 4

Соответственно алгоритм может быть примерно такой:

  1. Применяем детектор краев после сильного размытия. Не обязательно Кенни, чтобы не мучиться подбором параметров, можно даже Собеля или Лапласа попробовать. Лапласа лучше тем, что линия будет тонкой, но надо смотреть что получится.
  2. Пишем упрощенную реализацию линий Хафа - проводим кандидаты на линии там, где они могут быть(горизонтально, вертикально и под небольшими углами на правдоподобном расстоянии от центра/границ) и считаем сумму попавших под них белых точек, деленную на длину линии. 
  3. Применяем этот алгоритм к результату едж-детектора, выбираем две самые сильные примерно горизонтальные и примерно вертикальные линии, получаем прямоугольник.
  4. В пределах прямоугольника порогом Оцу получаем цифры.
  • Like 1

Share this post


Link to post
Share on other sites

Спасибо за ответ, давненько не отписывал в тему. Сейчас программа умеет так(спасибо тов. iskees):

post-7270-0-33050900-1429768886_thumb.jp

Теперь мучаюсь с нахождением трёх точек для выполнения аффинных преобразований.

Share this post


Link to post
Share on other sites

У тебя получился отличный результат.

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

  • Like 1

Share this post


Link to post
Share on other sites

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

Код, который это делает:

upd. Нашел интересный ConvexHull, попробую.

 using (MemStorage storage = new MemStorage())
            {

                for (Contour<Point> contours = grayImage.FindContours(Emgu.CV.CvEnum.CHAIN_APPROX_METHOD.CV_CHAIN_APPROX_SIMPLE, Emgu.CV.CvEnum.RETR_TYPE.CV_RETR_TREE, storage); contours != null; contours = contours.HNext)
                {

                    Contour<Point> currentContour = contours.ApproxPoly(contours.Perimeter * 0.015, storage);
                    if (currentContour.BoundingRectangle.Width > 20)
                    {
                        //Здесь бы собрать подходящие контуры в новый массив
                        CvInvoke.cvDrawContours(color, contours, new MCvScalar(255), new MCvScalar(0), -1, 3, Emgu.CV.CvEnum.LINE_TYPE.EIGHT_CONNECTED, new Point(0, 0));
                        color.Draw(currentContour.BoundingRectangle, new Bgr(0, 0, 255), 1);
                    }
                }

            }
               //А после перегнать их в прямоугольник(область), которой сделать новое изображение

post-7270-0-51803600-1430826611_thumb.jp

Share this post


Link to post
Share on other sites

1. Самый элементарный способ ускорения - сделать так, чтобы приближение происходило не попиксельно, а с некоторым шагом. Например, поначалу с шагом побольше, а далее, по мере улучшения показателей, шаг уменьшать. Типа как градиентный метод.

2. Далее. Что самое медленное в методе? Логика подсказывает, что вычисление среднего, то есть многократный проход по памяти. Такие вещи обычно оптимизируются с помощью интегральных изображений. Тогда среднее значение по области будет вычисляться как 3 операции сложения и одно деление. Но этот метод будет реализовать уже не так тривиально.

 

Вот набросал вариант с вариантом первой оптимизации:

#include <memory>
#include <string>
#include <iostream>
#include <vector>

#include <opencv2/opencv.hpp>


#define DBG_WND 1

/**
***************************************************************************************************
*  RectFinder
*
*   @brief
*      Search an accurate rectangle position on an image: iterative mean and gradient of the mean calculation
***************************************************************************************************
*/

class RectFinder
{
public:
    RectFinder()
    {
    }
    ~RectFinder()
    {
    }
    
    /**
    ***************************************************************************************************
    *  RectFinder::FindRect
    *
    *   @brief
    *      Find an accurate rectangle position
    ***************************************************************************************************
    */
    bool RectFinder::FindRect(
            cv::Mat img,
            cv::RotatedRect& resultPos
            )
    {
        resultPos = cv::RotatedRect(cv::Point2f(img.cols / 2.0f, img.rows / 2.0f),
                                    cv::Size(img.cols - img.cols / 3, img.rows - img.rows / 5),
                                    0);
        cv::RotatedRect drr;
#if DBG_WND
        cv::Mat img_cpy;
#endif
        
        float last_l[2] = { 0, 0 };
        float kw = 4.0f;
        float kh = 2.0f;
        for (int i = 0; i < MaxIterations; ++i)
        {
#if DBG_WND
            img_cpy = img.clone();
#endif
            
            float l0 = GetLikelihoodGradient(img, resultPos, drr);
            
            const float delta = last_l[0] - l0;
            if (fabs(delta) < 0.1f &&
                    kw > 2.0f &&
                    kh > 1.0f)
            {
                kw = 2.0f;
                kh = 1.0f;
            }
            else if (fabs(delta) < 0.01f &&
                     kw > 1.0f)
            {
                kw = 1.0f;
                kh = 1.0f;
            }
            else if (fabs(delta) < 0.001f ||
                     fabs(last_l[1] - l0) < 0.001f)
            {
#if DBG_WND
                std::cout << i << ": " << l0 << ", kw = " << kw << ", kh = " << kh << ", break" << std::endl;
#endif
                break;
            }
            last_l[0] = last_l[1];
            last_l[1] = l0;
            
#if DBG_WND
            std::cout << i << ": " << l0 << ", kw = " << kw << ", kh = " << kh << std::endl;
#endif
            
            // Change parameters for increese distance between mean colors
            resultPos.center += drr.center;
            resultPos.size.width += kw * drr.size.width;
            resultPos.size.height += kh * drr.size.height;
            resultPos.angle += drr.angle;
            
#if DBG_WND
            cv::Point2f rect_points[4];
            resultPos.points(rect_points);
            
            for (int j = 0; j < 4; j++)
            {
                cv::line(img_cpy, rect_points[j], rect_points[(j + 1) % 4], cv::Scalar(0, 255, 0), 1, CV_AA);
            }
            
            cv::imshow("img_cpy", img_cpy);
            cv::waitKey(100);
#endif
        }
        
        return true;
    }
    
private:
    /**
    ***************************************************************************************************
    *  RectFinder::GetLikelihood
    *
    *   @brief
    *      Calculation distance between colors
    ***************************************************************************************************
    */
    float RectFinder::GetLikelihood(
            cv::Mat img,
            cv::RotatedRect& rr
            )
    {
        double likelihood = 0;
        cv::Mat mask = cv::Mat::zeros(img.size(), CV_8UC1);
        // rotated rectangle
        cv::Point2f rect_points[4];
        rr.points(rect_points);
        std::vector<cv::Point> pts(4);
        for (int i = 0; i < 4; ++i)
        {
            pts[i] = rect_points[i];
        }
        cv::fillConvexPoly(mask, pts, cv::Scalar::all(255));
#if DBG_WND
        imshow("mask", 255 - mask);
#endif
        cv::Scalar cc1 = cv::mean(img, mask);
        cv::Scalar cc2 = cv::mean(img, 255 - mask);
        likelihood = cv::norm(cc1, cc2, cv::NORM_L2);
        return likelihood;
    }
    
    /**
    ***************************************************************************************************
    *  RectFinder::GetLikelihoodGradient
    *
    *   @brief
    *      Calculation mean gradient
    ***************************************************************************************************
    */
    float RectFinder::GetLikelihoodGradient(
            cv::Mat img,
            cv::RotatedRect& rr,
            cv::RotatedRect& drr
            )
    {
        cv::RotatedRect rrdx = rr;
        rrdx.center.x += 1;
        cv::RotatedRect rrdy = rr;
        rrdy.center.y += 1;
        cv::RotatedRect rrdw = rr;
        rrdw.size.width += 1;
        cv::RotatedRect rrdh = rr;
        rrdh.size.height += 1;
        cv::RotatedRect rrdang = rr;
        rrdang.angle += 1;
        
        cv::RotatedRect rrdxn = rr;
        rrdxn.center.x -= 1;
        cv::RotatedRect rrdyn = rr;
        rrdyn.center.y -= 1;
        cv::RotatedRect rrdwn = rr;
        rrdwn.size.width -= 1;
        cv::RotatedRect rrdhn = rr;
        rrdhn.size.height -= 1;
        cv::RotatedRect rrdangn = rr;
        rrdangn.angle -= 1;
        
        float l0 = GetLikelihood(img, rr);
        
        float dlx = GetLikelihood(img, rrdx) - GetLikelihood(img, rrdxn);
        float dly = GetLikelihood(img, rrdy) - GetLikelihood(img, rrdyn);
        float dlw = GetLikelihood(img, rrdw) - GetLikelihood(img, rrdwn);
        float dlh = GetLikelihood(img, rrdh) - GetLikelihood(img, rrdhn);
        float dlang = GetLikelihood(img, rrdang) - GetLikelihood(img, rrdangn);
        
        float scale = sqrt(dlx * dlx + dly * dly + dlw * dlw + dlh * dlh + dlang * dlang);
        
        dlx /= scale;
        dly /= scale;
        dlw /= scale;
        dlh /= scale;
        dlang /= scale;
        
        drr.center.x = dlx;
        drr.center.y = dly;
        drr.size.width = dlw;
        drr.size.height = dlh;
        drr.angle = dlang;
        
        return l0;
    }
    
    static const int MaxIterations = 1000; ///< Maximum itarations count for the search of number rectangle
};


/**
*******************************************************************************
*
*   main
*
*******************************************************************************
*/
int main(int argc, char* argv[])
{
    std::string fileName("number_img.png");
    int initLeft = 108;
    int initRight = 186;
    int initTop = 210;
    int initBottom = 227;
    if (argc > 1)
    {
        fileName = argv[1];
    }
    if (argc > 5)
    {
        initLeft = atoi(argv[2]);
        initRight = atoi(argv[3]);
        initTop = atoi(argv[4]);
        initBottom = atoi(argv[5]);
    }
    std::string resultImageFile = "";
    if (argc > 6)
    {
        resultImageFile = argv[6];
    }
    int initWidth = initRight - initLeft;
    int initHeight = initBottom - initTop;
    
    cv::Mat img = cv::imread(fileName);
    
#if DBG_WND
    cv::Mat dbgImg;
    img.copyTo(dbgImg);
    cv::namedWindow("testing", cv::WINDOW_AUTOSIZE);
    cv::imshow("testing", dbgImg);
    cv::waitKey(10);
#endif
    
    int left = std::max(0, initLeft - initWidth / 5);
    int right = std::min(img.cols - 1, initRight + initWidth / 5);
    int top = std::max(0, initTop - initHeight / 5);
    int bottom = std::min(img.rows - 1, initBottom + initHeight / 5);
    
    std::shared_ptr<RectFinder> rectFinder = std::make_shared<RectFinder>();
    
    double freq = cv::getTickFrequency();
    int64 t1 = cv::getTickCount();
    cv::RotatedRect resultPos;
    rectFinder->FindRect(cv::Mat(img, cv::Rect(left, top, right - left, bottom - top)), resultPos);
    int64 t2 = cv::getTickCount();
    
    std::cout << "work_time=" << ((t2 - t1) / freq) <<
                 " angle=" << resultPos.angle <<
                 " width=" << resultPos.size.width <<
                 " height=" << resultPos.size.height <<
                 " cx=" << left + resultPos.center.x <<
                 " cy=" << top + resultPos.center.y << std::endl;
    
    if (!resultImageFile.empty())
    {
        cv::Mat resImg = cv::imread(resultImageFile);
        
        cv::rectangle(resImg, cv::Rect(initLeft, initTop, initWidth, initHeight), cv::Scalar(255, 0, 0), 1, CV_AA);
        
        cv::Point2f rectPoints[4];
        resultPos.points(rectPoints);
        for (int j = 0; j < 4; j++)
        {
            cv::Point p1(left + rectPoints[j].x, top + rectPoints[j].y);
            cv::Point p2(left + rectPoints[(j + 1) % 4].x, top + rectPoints[(j + 1) % 4].y);
            cv::line(resImg, p1, p2, cv::Scalar(0, 255, 0), 1, CV_AA);
        }
        
        cv::imwrite(resultImageFile, resImg);
    }
#if DBG_WND
    cv::rectangle(dbgImg, cv::Rect(initLeft, initTop, initWidth, initHeight), cv::Scalar(255, 0, 0), 1, CV_AA);
    
    cv::Point2f rectPoints[4];
    resultPos.points(rectPoints);
    for (int j = 0; j < 4; j++)
    {
        cv::Point p1(left + rectPoints[j].x, top + rectPoints[j].y);
        cv::Point p2(left + rectPoints[(j + 1) % 4].x, top + rectPoints[(j + 1) % 4].y);
        
        cv::line(dbgImg, p1, p2, cv::Scalar(0, 255, 0), 1, CV_AA);
    }
    
    cv::imshow("testing", dbgImg);
    cv::waitKey(0);
    cv::destroyAllWindows();
#endif
    
    return 0;
}

Share this post


Link to post
Share on other sites

Спасибо за такой развернутый ответ! Однако, я довольно плохой программист и перенести этот код в с# у меня не получилось. Хотелось бы справиться стандартными возможностями c# и emgucv. Повозился с houghlines, сначала получалась какая то каша в виде огромного количества линий, теперь же они находятся прямо там, где нужно! Осталось вот теперь как нибудь обрезать по ним изображение,  пошёл искать как бы это сделать.

post-7270-0-74911200-1430845704_thumb.jp

Share this post


Link to post
Share on other sites

Ммм, логично было бы выровнять номер, а после уже работать лишь с ним.

Для этого найти по 4-м новым углам матрицу гомографии (findHomography) и вызвать warpPerspective.

  • Like 1

Share this post


Link to post
Share on other sites

Ох, раньше не увидел, но пока сделал методом "в лоб" - поворачиванием изображения на известный угол наклона прямоугольника.Столкнулся с сегментацией, а именно, я рассчитывал что через findContours можно выделить в прямоугольники каждый символ и потом их распознавать. Оказывается, я или ошибался насчет этой идеи, либо делаю что то неправильно- все цифры хорошо выделяются через  CvInvoke.cvDrawContours(temp4, contours, new MCvScalar(0), new MCvScalar(255), -1, 3, Emgu.CV.CvEnum.LINE_TYPE.EIGHT_CONNECTED, new Point(0, 0)); Но если вызвать temp4.Draw(currentContour.GetMinAreaRect(), new Bgr(0,0,255), 1);  или тоже самое с currentContour.BoundingRectanle программа рисует огромный квадрат во весь номер. Может подскажите, есть какие нибудь методы по выделению внутренних контуров, вместо одного большого?

post-7270-0-83626500-1430936631_thumb.jp

Share this post


Link to post
Share on other sites

Таких методов я не нашел, поэтому пока строю проекцию на ось Х, думаю находить лок.мин-мы для сегментации.

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

Edited by barsukov

Share this post


Link to post
Share on other sites

Такая странная незадача выходит. Проходя по изображению получается список точек в виде:

+ [0] {X = 2 Y = 204} System.Drawing.Point
+ [1] {X = 10 Y = 245} System.Drawing.Point
+ [2] {X = 22 Y = 181} System.Drawing.Point
+ [3] {X = 24 Y = 177} System.Drawing.Point
+ [4] {X = 34 Y = 219} System.Drawing.Point
+ [5] {X = 46 Y = 188} System.Drawing.Point
+ [6] {X = 60 Y = 231} System.Drawing.Point
Нужны точки(примерно) с коорд.Х 10,35,60 и т.д с разницей около 24. Но просто проходом и сравнением (текущаяточка - следующая) >= 24 массив не получается, т.к он каждый раз переходит на следующий элемент, я думал обойти это при каждом удачном нахождении точки запоминать текущее i и потом начинать цикл с него:
        public List<Point> FilterPoints(List<Point> inputPoints)
        {
            List<Point> sort_p = new List<Point>();
            int D = 24;                                 //Примерное удаление символов друг от друга, должно быть 24
            int first_i = 0;
            int i = 0;
            for (first_i = i ; i < inputPoints.Count - 1; i++) 
            {
                if ((inputPoints[i].X >= 10) || (Math.Abs(inputPoints[i].X - inputPoints[i + 1].X) >= D))  //Первое условие- лишнее пространство в начале изображения
                { sort_p.Add(new Point(inputPoints[i].X, 0)); first_i = i; }
            }


            return sort_p;
        }
Но метод выводит 0 точек, если делать переменную D около 10- слишком много точек. Подскажите, пожалуйста, где я ошибся в алгоритме?

 

Share this post


Link to post
Share on other sites

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

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

Плюс такого  подхода в том, что погрешности нахождения искомых точек нам уже не страшны.

Share this post


Link to post
Share on other sites

Точно! Поставлю условие и буду выбирать из диапазона где скорее всего находятся точки, спасибо!

Share this post


Link to post
Share on other sites

Сделал фильтрацию таким методом:

public List<Point> FilterPoints(List<Point> inputPoints)
        {
            List<Point> sort_p = new List<Point>();
            for (int i = 0; i < inputPoints.Count; i++)
            {
                if ((inputPoints[i].X >= 7 && inputPoints[i].X <= 12) || (inputPoints[i].X >= 32 && inputPoints[i].X <= 38) ||
                    (inputPoints[i].X >= 60 && inputPoints[i].X <= 70) || (inputPoints[i].X >= 85 && inputPoints[i].X <= 100) ||
                    (inputPoints[i].X >= 111 && inputPoints[i].X <= 127) || (inputPoints[i].X >= 139 && inputPoints[i].X <= 153) ||
                    (inputPoints[i].X >= 164 && inputPoints[i].X <= 184))
                { sort_p.Add(new Point(inputPoints[i].X, 0)); }
            }


            for (int i = 0; i < sort_p.Count - 3; i++)
            {
                if ((Math.Abs(sort_p[i].X - sort_p[i + 2].X) < 20))
                {
                    if (sort_p[i + 2].IsEmpty == false) sort_p.RemoveAt(i + 2);
                }
            }


                for (int i = 0; i < sort_p.Count - 1; i++)
                {
                    if (Math.Abs(sort_p[i].X - sort_p[i + 1].X) < 15) sort_p.RemoveAt(i + 1);
                }
                if (sort_p.Count > 7)
                {
                    for (int i = 0; i < sort_p.Count - 1; i++)
                    {
                        if (Math.Abs(sort_p[i].X - sort_p[i + 1].X) < 20) sort_p.RemoveAt(i + 1);
                    }
                }
                return sort_p;
            }
Немного топорно, понимаю, но работает :)

Share this post


Link to post
Share on other sites

После выделения символов занялся распознаванием, нашел достаточно готовых алгоритмов, но очень уж хочется попробовать для начала простую ИНС. Нашёл эту статью, в ней довольно хорошо расписана простенькая сеть Хопфилда, но столкнулся с ошибкой(картинка)(outOfRangeException) на этапе преобразования картинки в вектор значений "1 и -1". Vector заполняется до 1074 элемента, всего он рассчитан на 1075, не пойму где он выходит за границы, подскажите, пожалуйста.

        public int[] ConvertToVector(Bitmap Image)
        {
            
            int[] Vector = new int[Image.Width * Image.Height];


            for (int i = 0; i < Image.Height; i++)
            {
                for (int j = 0; j < Image.Width; j++)
                {
                    Vector[j + (i * Image.Height)] = Sigma(Image.GetPixel(i, j));
                }
            }
            return Vector;
        }

post-7270-0-86740100-1431867165_thumb.jp

Share this post


Link to post
Share on other sites

Vector[j + (i * Image.Height)]  на ширину умножайте, а не на высоту

и в  bitmap GetPixel( x, y)   в opencv наоборот 

Share this post


Link to post
Share on other sites

Ребят, появился такой вопрос. В детекторе границ Канни используется гауссовая маска и сигма. Можно ли каким нибудь образом в EmguCV задавать эти параметры в методе .Canny() или другими способами? И если нельзя, есть ли какое нибудь объяснение какие значения использует Emgu по умолчанию?

upd. А вот, по умолчанию маска = 3. но сигму видимо никак нельзя задавать

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now


  • Recently Browsing   0 members

    No registered users viewing this page.

×