Перейти к содержимому
Compvision.ru
K0rG

Распознавание номерного знака, расп. текста.

Recommended Posts

Открытый движок распознавания символов:

http://jocr.sourceforge.net/

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Открытый движок распознавания символов:

http://jocr.sourceforge.net/

а еще очень не плох tesseract от HP, кажется. сейчас выложен GOOGLE: http://code.google.com/p/tesseract-ocr/

правда, есть нюансы с русским языком

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Необходимо распознать текст на однотонном фоне (шрифт стандартный, например, Times New Roman) с определенной области изображения.

За счет каких функций, решений это можно осуществить?

Заранее спасибо.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Необходимо распознать текст на однотонном фоне (шрифт стандартный, например, Times New Roman) с определенной области изображения.

За счет каких функций, решений это можно осуществить?

Заранее спасибо.

Думаю, так просто, как Вы думаете, не получится. Более того, OpenCV, ИМХО, не обладает таким потенциалом в области OCR, как специализированные разработки. Сталкивался с tesseract - вполне себе понравилось, и лицензия хорошая.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Думаю, так просто, как Вы думаете, не получится. Более того, OpenCV, ИМХО, не обладает таким потенциалом в области OCR, как специализированные разработки. Сталкивался с tesseract - вполне себе понравилось, и лицензия хорошая.

tesseract неплох, это правда. еще понравились реализации подобных проблем с использованием нейронных сетей. обучается, правда, долго, но результат - как раз под описание проблемы

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Необходимо распознать текст на однотонном фоне (шрифт стандартный, например, Times New Roman) с определенной области изображения.

За счет каких функций, решений это можно осуществить?

Заранее спасибо.

Можно использовать CuneiForm. Автоматизация через COM-сервер Puma. Лицензия тоже хорошая.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Спасибо всем за предложенные советы.

Попробовал tesseract - взял с GoogleCode библиотеку, стандартную дату для распознавания английского текста, попробовал.

На шрифтах размера больше 14го работает замечательно. Но в моем случае шрифт приблизительно 8-9. Его в упор не видит. Пробовал увеличивать изображение 2-3 раза и распознавать - обнаруживает, что есть текст, но выдает полную кашу.

Попробовал MODI(Microsoft Office Document Imaging). Распознает мелкий текст нормально - цифры без ошибок, а вот сочетания букв fd fl коряво.

Буду пробовать другие библиотеки.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
tesseract неплох, это правда. еще понравились реализации подобных проблем с использованием нейронных сетей. обучается, правда, долго, но результат - как раз под описание проблемы

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

Поделиться сообщением


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

Вот, если попробовать только http://xpidea.com/Products/tabid/53/Produc...10/Default.aspx

а так google в помощь - попадались реализации

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Насколько я помню в номерном знаке могут присутствовать цифры от 0 до 9 и буквы(А, В, Е, К, М, Н, О, Р, С, Т, У, Х).

Успехов! :D

post-1174-1283702670_thumb.jpg

post-1174-1283702678_thumb.jpg

post-1174-1283702683_thumb.jpg

post-1174-1283703046_thumb.png

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Успехов! :D

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

Например, стандарт Беларуси: http://www.gosstandart.gov.by/txt/BDD_pdf/914.pdf

Поделиться сообщением


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

Какое дело иностранцу на автомобиле (из той же России, Украины) до внутренних актов, по которым Белорусия выпускает свои номера?

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

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

Суть идеи пока такая:

1. Получаем картинку с камеры.

2. Определяем наличие движения.

3. Когда присутствует движение - выхватываем его и ищем на нём автомобильные номера.

4. Вырезаем этот самый номер.

5. Распознаем номер.

Собственно, подскажите пожалуйста, где я прав или не прав, какие функции можно дёргать.... спасибо за любую помощь!

Для начала есть (взято с примеров) - получение изображения с камеры и детектирование движения:

#include "cv.h"

#include "highgui.h"

#include <time.h>

#include <math.h>

#include <ctype.h>

#include <stdio.h>


// various tracking parameters (in seconds)

const double MHI_DURATION = 1;

const double MAX_TIME_DELTA = 0.5;

const double MIN_TIME_DELTA = 0.05;


// number of cyclic frame buffer used for motion detection

// (should, probably, depend on FPS)

const int N = 5;


// ring image buffer

IplImage **buf = 0;

int last = 0;


// temporary images


IplImage *mhi = 0; // MHI

IplImage *orient = 0; // orientation

IplImage *mask = 0; // valid orientation mask

IplImage *segmask = 0; // motion segmentation map

CvMemStorage* storage = 0; // temporary storage


// parameters:

//  img – input video frame

//  dst – resultant motion picture

//  args – optional parameters


void  update_mhi( IplImage* img, IplImage* dst, int diff_threshold )

{

    double timestamp = (double)clock()/CLOCKS_PER_SEC; // get current time in seconds

    CvSize size = cvSize(img->width,img->height); // get current frame size

    int i, idx1 = last, idx2;

    IplImage* silh;

    CvSeq* seq;

    CvRect comp_rect;

    double count;

    double angle;


    double magnitude;         

    CvScalar color;



    // allocate images at the beginning or

    // reallocate them if the frame size is changed


    if( !mhi || mhi->width != size.width || mhi->height != size.height ) 

	{

        if( buf == 0 ) 

		{

            buf = (IplImage**)malloc(N*sizeof(buf[0]));

            memset( buf, 0, N*sizeof(buf[0]));

		}


        for( i = 0; i < N; i++ ) 

		{

            cvReleaseImage( &buf[i] );

            buf[i] = cvCreateImage( size, IPL_DEPTH_8U, 1 );

            cvZero( buf[i] );

        }


        cvReleaseImage( &mhi );

        cvReleaseImage( &orient );

        cvReleaseImage( &segmask );

        cvReleaseImage( &mask );


        mhi = cvCreateImage( size, IPL_DEPTH_32F, 1 );

        cvZero( mhi ); // clear MHI at the beginning

        orient = cvCreateImage( size, IPL_DEPTH_32F, 1 );

        segmask = cvCreateImage( size, IPL_DEPTH_32F, 1 );

        mask = cvCreateImage( size, IPL_DEPTH_8U, 1 );

    }




    cvCvtColor( img, buf[last], CV_BGR2GRAY ); // convert frame to grayscale


    idx2 = (last + 1) % N; // index of (last – (N-1))th frame

    last = idx2;

    silh = buf[idx2];

    cvAbsDiff( buf[idx1], buf[idx2], silh ); // get difference between frames   


    cvThreshold( silh, silh, diff_threshold, 1, CV_THRESH_BINARY ); // and threshold it

    cvUpdateMotionHistory( silh, mhi, timestamp, MHI_DURATION ); // update MHI


    // convert MHI to blue 8u image

    cvCvtScale( mhi, mask, 255./MHI_DURATION,


                (MHI_DURATION - timestamp)*255./MHI_DURATION );

    cvZero( dst );

    cvCvtPlaneToPix( mask, 0, 0, 0, dst ); 


    // calculate motion gradient orientation and valid orientation mask

    cvCalcMotionGradient( mhi, mask, orient, MAX_TIME_DELTA, MIN_TIME_DELTA, 3 );


    if( !storage )

        storage = cvCreateMemStorage(0);

    else

        cvClearMemStorage(storage);   

    // segment motion: get sequence of motion components

    // segmask is marked motion components map. It is not used further

    seq = cvSegmentMotion( mhi, segmask, storage, timestamp, MAX_TIME_DELTA ); 


    // iterate through the motion components,

    // One more iteration (i == -1) corresponds to the whole image (global motion)

    for( i = -1; i < seq->total; i++ ) 

	{ 

        if( i < 0 ) 

		{ // case of the whole image

            comp_rect = cvRect( 0, 0, size.width, size.height );

            color = CV_RGB(255,255,255);

            magnitude = 100;

        }

        else { // i-th motion component

            comp_rect = ((CvConnectedComp*)cvGetSeqElem( seq, i ))->rect;

            if( comp_rect.width + comp_rect.height < 100 ) // reject very small components

                continue;

            color = CV_RGB(255,0,0);

            magnitude = 30;

        }

        // select componen ROI

        cvSetImageROI( silh, comp_rect );

        cvSetImageROI( mhi, comp_rect );

        cvSetImageROI( orient, comp_rect );

        cvSetImageROI( mask, comp_rect );

        // calculate orientation

        angle = cvCalcGlobalOrientation( orient, mask, mhi, timestamp, MHI_DURATION);

        angle = 360.0 - angle;  // adjust for images with top-left origin

        count = cvNorm( silh, 0, CV_L1, 0 ); // calculate number of points within silhouette ROI

        cvResetImageROI( mhi );

        cvResetImageROI( orient );

        cvResetImageROI( mask );

        cvResetImageROI( silh ); 

        // check for the case of little motion

        if( count < comp_rect.width*comp_rect.height * 0.05 )

            continue;

    }

}






int main(int argc, char** argv)

{

    IplImage* motion = 0;

    CvCapture* capture = 0; 


    if( argc == 1 || (argc == 2 && strlen(argv[1]) == 1 && isdigit(argv[1][0])))

        capture = cvCaptureFromCAM( argc == 2 ? argv[1][0] - '0' : 0 );

    else if( argc == 2 )

        capture = cvCaptureFromFile( argv[1] );

    if( capture )

    {

        cvNamedWindow( "Motion", 1 );

		cvNamedWindow( "Original", 2 );

        for(;

        {

            IplImage* image;

            if( !cvGrabFrame( capture ))

                break;

            image = cvRetrieveFrame( capture );

            if( image )

            {

                if( !motion )

                {

                    motion = cvCreateImage( cvSize(image->width,image->height), 8, 3 );

                    cvZero( motion );

                    motion->origin = image->origin;

                }

            }


            update_mhi( image, motion, 30 );

			cvShowImage( "Original", image );

            cvShowImage( "Motion", motion );


//			cvAbsDiff();


            if( cvWaitKey(10) >= 0 )

                break;

        }

        cvReleaseCapture( &capture );

		cvDestroyAllWindows();

    }

    return 0;

}




[/code]

Вопрос первый, как по полученному движению - вырезать область движения (прямоугольную) из оригинального изображения?

Вопрос второй, как искать номер? - Каскады Хаара, наверное слишком для этого?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Очень уж крупноблочно :)

не вызывает вопросов только первый и четвертый пункт.

По остальным есть такие соображения:

2: движение в кадре лучше определять не шаблонами движения, а хотя бы как в примерах bgfg_codebook или bgfg_segm.

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

При идеальной бинаризации можно попробовать искать прямоугольник, как в примерах (squares.c).

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

5: Для распознавания есть спец. библиотеки с открытым кодом (ссылки на них есть на форуме).

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Уже успел встроить в код поиск прямоугольников из вышеупомянутого примера!... Работает конечно кривова-то: находит всё, что ни попадя... И бинаризация, кстати, хорошая идея для решения части из проблем.

Пока решил попробовать, с определённой частотой, например 6 кадров в секунду, брать изображение и искать на нём прямоугольники... Тут отпадёт необходимость поиска движения! И если есть прямоугольники - то пытаться их распознавать, при этом их отфильтровав: Очевидно, что их верхняя и нижняя стороны примерно равны, тоже и с правой - левой, а боковинки будут меньше, чем верхушки.... Коечно в расчёт берётся то, что номер мы получаем без искажений.

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

Есть встроеные функции для бинаризации?

Код после небольшой оптимизации выложу для желающих.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

cvThreshold,cvAdaptiveThreshold.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

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

Кто знает, как бороться?

#ifdef _CH_

#pragma package <opencv>

#endif


#define CV_NO_BACKWARD_COMPATIBILITY


#include "cv.h"

#include "highgui.h"

#include <time.h>

#include <math.h>

#include <ctype.h>

#include <stdio.h>

#include <string.h>


int thresh = 50;

IplImage* img = 0;

IplImage* img0 = 0;

CvMemStorage* storage = 0;

const char* wndname = "Square Detection";



double angle( CvPoint* pt1, CvPoint* pt2, CvPoint* pt0 )

{

    double dx1 = pt1->x - pt0->x;

    double dy1 = pt1->y - pt0->y;

    double dx2 = pt2->x - pt0->x;

    double dy2 = pt2->y - pt0->y;

    return (dx1*dx2 + dy1*dy2)/sqrt((dx1*dx1 + dy1*dy1)*(dx2*dx2 + dy2*dy2) + 1e-10);

}


CvSeq* findSquares4( IplImage* img, CvMemStorage* storage )

{

    CvSeq* contours;

    int i, c, l, N = 11;

    CvSize sz = cvSize( img->width & -2, img->height & -2 );

    IplImage* timg = cvCloneImage( img ); // make a copy of input image

    IplImage* gray = cvCreateImage( sz, 8, 1 );

    IplImage* pyr = cvCreateImage( cvSize(sz.width/2, sz.height/2), 8, 3 );

    IplImage* tgray;

    CvSeq* result;

    double s, t;

    // create empty sequence that will contain points -

    // 4 points per square (the square's vertices)

    CvSeq* squares = cvCreateSeq( 0, sizeof(CvSeq), sizeof(CvPoint), storage );


    // select the maximum ROI in the image

    // with the width and height divisible by 2

    cvSetImageROI( timg, cvRect( 0, 0, sz.width, sz.height ));


    // down-scale and upscale the image to filter out the noise

    cvPyrDown( timg, pyr, 7 );

    cvPyrUp( pyr, timg, 7 );

    tgray = cvCreateImage( sz, 8, 1 );


    // find squares in every color plane of the image

    for( c = 0; c < 3; c++ )

    {

        // extract the c-th color plane

        cvSetImageCOI( timg, c+1 );

        cvCopy( timg, tgray, 0 );


        // try several threshold levels

        for( l = 0; l < N; l++ )

        {

            // hack: use Canny instead of zero threshold level.

            // Canny helps to catch squares with gradient shading

            if( l == 0 )

            {

                // apply Canny. Take the upper threshold from slider

                // and set the lower to 0 (which forces edges merging)

                cvCanny( tgray, gray, 0, thresh, 5 );

                // dilate canny output to remove potential

                // holes between edge segments

                cvDilate( gray, gray, 0, 1 );

            }

            else

            {

                // apply threshold if l!=0:

                //     tgray(x,y) = gray(x,y) < (l+1)*255/N ? 255 : 0

                cvThreshold( tgray, gray, (l+1)*255/N, 255, CV_THRESH_BINARY );

            }


            // find contours and store them all as a list

            cvFindContours( gray, storage, &contours, sizeof(CvContour),

                CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE, cvPoint(0,0) );


            // test each contour

            while( contours )

            {

                // approximate contour with accuracy proportional

                // to the contour perimeter

                result = cvApproxPoly( contours, sizeof(CvContour), storage,

                    CV_POLY_APPROX_DP, cvContourPerimeter(contours)*0.02, 0 );

                // square contours should have 4 vertices after approximation

                // relatively large area (to filter out noisy contours)

                // and be convex.

                // Note: absolute value of an area is used because

                // area may be positive or negative - in accordance with the

                // contour orientation

                if( result->total == 4 &&

                    cvContourArea(result,CV_WHOLE_SEQ,0) > 1000 &&

                    cvCheckContourConvexity(result) )

                {

                    s = 0;


                    for( i = 0; i < 5; i++ )

                    {

                        // find minimum angle between joint

                        // edges (maximum of cosine)

                        if( i >= 2 )

                        {

                            t = fabs(angle(

                            (CvPoint*)cvGetSeqElem( result, i ),

                            (CvPoint*)cvGetSeqElem( result, i-2 ),

                            (CvPoint*)cvGetSeqElem( result, i-1 )));

                            s = s > t ? s : t;

                        }

                    }


                    // if cosines of all angles are small

                    // (all angles are ~90 degree) then write quandrange

                    // vertices to resultant sequence

                    if( s < 0.3 )

                        for( i = 0; i < 4; i++ )

                            cvSeqPush( squares,

                                (CvPoint*)cvGetSeqElem( result, i ));

                }


                // take the next contour

                contours = contours->h_next;

            }

        }

    }


    // release all the temporary images

    cvReleaseImage( &gray );

    cvReleaseImage( &pyr );

    cvReleaseImage( &tgray );

    cvReleaseImage( &timg );


    return squares;

}


void drawSquares( IplImage* img, CvSeq* squares )

{

    CvSeqReader reader;

    IplImage* cpy = cvCloneImage( img );

    int i;


    // initialize reader of the sequence

    cvStartReadSeq( squares, &reader, 0 );


    // read 4 sequence elements at a time (all vertices of a square)

    for( i = 0; i < squares->total; i += 4 )

    {

        CvPoint pt[4], *rect = pt;

        int count = 4;


        // read 4 vertices

        CV_READ_SEQ_ELEM( pt[0], reader );

        CV_READ_SEQ_ELEM( pt[1], reader );

        CV_READ_SEQ_ELEM( pt[2], reader );

        CV_READ_SEQ_ELEM( pt[3], reader );


        // draw the square as a closed polyline

        cvPolyLine( cpy, &rect, &count, 1, 1, CV_RGB(0,255,0), 3, CV_AA, 0 );

    }


    // show the resultant image

    cvShowImage( wndname, cpy );

    cvReleaseImage( &cpy );

}






IplImage* frame = 0;

IplImage* imgForSquare = 0;

IplImage* imgGray = 0;

IplImage* imgBinary = 0;


int main()

{

	storage = cvCreateMemStorage(0);


	cvNamedWindow("original",CV_WINDOW_AUTOSIZE);

	//cvNamedWindow("gray",CV_WINDOW_AUTOSIZE);

	cvNamedWindow("binary",CV_WINDOW_AUTOSIZE);


	CvCapture* capture = cvCreateCameraCapture(CV_CAP_ANY);


    while(1)

	{

		frame = cvQueryFrame( capture );


		imgGray = cvCreateImage(cvGetSize(frame), frame->depth, 1);

		cvConvertImage(frame, imgGray, CV_BGR2GRAY);	

		imgBinary = cvCreateImage( cvGetSize(imgGray), IPL_DEPTH_8U, 1);

		//cvAdaptiveThreshold(imgGray, imgBinary, 50, 250, CV_THRESH_BINARY);

		cvAdaptiveThreshold(imgGray, imgBinary, 250, CV_ADAPTIVE_THRESH_GAUSSIAN_C, CV_THRESH_BINARY, 5, 3);


        if( !frame ) 

		{

			break;

        }


		drawSquares( frame, findSquares4( frame, storage ) );

        cvShowImage( "original", frame );

        //cvShowImage( "gray", imgGray );

		cvShowImage( "binary", imgBinary);


		//cvReleaseImage(&frame); cvReleaseImage(&imgGray); cvReleaseImage(&imgBinary);

//		drawSquares( imgGray, findSquares4( imgGray, storage ) );


        char c = cvWaitKey(33);

        if (c == 27) 

		{ 

			break;

        }

	 }

		cvClearMemStorage( storage );

        cvReleaseCapture( &capture );

		///cvReleaseImage(&frame); cvReleaseImage(&imgGray); cvReleaseImage(&imgBinary);

		cvDestroyAllWindows();

        return 0;

}

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Очень заинтересовался проектом, точнее вплотную принялся за подобную разработку.

Код выложенный anton - м действительно очень тормозной, и не всегда коректно находит прямоугольники. Утечка памяти изза того что не чистит MemStorage.

Перерыл море инфы на ткнулся вот на подобный алгоритм http://cms.tusur.ru/filearchive/reports-magazine/2008-2-1/34-39.pdf

заключается он в разбиение изображения на блоки и составления карты контрастности

Кто что может сказать про данный метод?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Итак перерыв форум, наткнулся на ссылочку http://www.inf.tsu.ru/library/DiplomaWorks/CompScience/2006/busigin/diplom.pdf

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

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

Если кто силен в математике, подскажите что делать.

Спасибо за рание.


int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])

{

	cvNamedWindow("Org");

	cvNamedWindow("Gray");

	IplImage* frame = NULL;

	frame = cvLoadImage("c:/O807MK177.jpg");


	IplImage* gray = NULL;


	gray = cvCreateImage(cvGetSize(frame), 8, 1);


	cvConvertImage(frame, gray, CV_BGR2GRAY);




	CvPoint ptLast = cvPoint(0, 0);


	DWORD dwStart = GetTickCount();

	int nLastYPos = 0;



	for (int nY = 0; nY < gray->height; nY+=10)

	{

		ptLast = cvPoint(0, nY);

		for (int nX = 0; nX < gray->widthStep - 2; nX++)

		{

			int nBr =  gray->imageData[nY * gray->widthStep + nX] / 10;

			int nBr1 =  gray->imageData[nY * gray->widthStep + nX + 1] / 10;


			nBr = abs(nBr1 - nBr);

			cvLine(frame, ptLast, cvPoint(nX, nY - nBr) , cvScalar(0), 1);

			ptLast = cvPoint(nX, nY - nBr);

		}

	}


	dwStart = GetTickCount() - dwStart;


	std::cout << dwStart;



	cvShowImage("Gray", gray);

	cvShowImage("Org", frame);


	cvReleaseImage(&gray);

	cvReleaseImage(&frame);


	gray = NULL;

	frame = NULL;


	char c = cvWaitKey(0);

	if (c == 27) 

	{ 

		return 0;

	}

	return 0;

}

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

ну производную, то в дискретном случае можно взять как (y2-y1)/(x2-x1).

как сглаживать и зачем не знаю.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Вторая производная: D2 y(i) = y(i - 1) - 2 * y(i) + y(i + 1)

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

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

И уже от сглаженной функции брать производные, тогда все получится :)

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

А подойдет ли следующие сглаживание:

к примеру беру пять точек и высчитываю среднее значение между ними?

т.е.

-2 -1 0 1 2, и ставлю полученнное значение на место 0-го элемента?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Создайте учётную запись или войдите для комментирования

Вы должны быть пользователем, чтобы оставить комментарий

Создать учётную запись

Зарегистрируйтесь для создания учётной записи. Это просто!

Зарегистрировать учётную запись

Войти

Уже зарегистрированы? Войдите здесь.

Войти сейчас


  • Сейчас на странице   0 пользователей

    Нет пользователей, просматривающих эту страницу

×