コード例 #1
0
ファイル: characteranalysis.cpp プロジェクト: Witek-/openalpr
Mat CharacterAnalysis::findOuterBoxMask()
{
    double min_parent_area = config->templateHeightPx * config->templateWidthPx * 0.10;	// Needs to be at least 10% of the plate area to be considered.

    int winningIndex = -1;
    int winningParentId = -1;
    int bestCharCount = 0;
    double lowestArea = 99999999999999;


    if (this->config->debugCharAnalysis)
        cout << "CharacterAnalysis::findOuterBoxMask" << endl;

    for (int imgIndex = 0; imgIndex < allContours.size(); imgIndex++)
    {
        //vector<bool> charContours = filter(thresholds[imgIndex], allContours[imgIndex], allHierarchy[imgIndex]);

        int charsRecognized = 0;
        int parentId = -1;
        bool hasParent = false;
        for (int i = 0; i < charSegments[imgIndex].size(); i++)
        {
            if (charSegments[imgIndex][i]) charsRecognized++;
            if (charSegments[imgIndex][i] && allHierarchy[imgIndex][i][3] != -1)
            {
                parentId = allHierarchy[imgIndex][i][3];
                hasParent = true;
            }
        }

        if (charsRecognized == 0)
            continue;

        if (hasParent)
        {
            double boxArea = contourArea(allContours[imgIndex][parentId]);
            if (boxArea < min_parent_area)
                continue;

            if ((charsRecognized > bestCharCount) ||
                    (charsRecognized == bestCharCount && boxArea < lowestArea))
                //(boxArea < lowestArea)
            {
                bestCharCount = charsRecognized;
                winningIndex = imgIndex;
                winningParentId = parentId;
                lowestArea = boxArea;
            }
        }


    }

    if (this->config->debugCharAnalysis)
        cout << "Winning image index is: " << winningIndex << endl;




    if (winningIndex != -1 && bestCharCount >= 3)
    {
        int longestChildIndex = -1;
        double longestChildLength = 0;
        // Find the child with the longest permiter/arc length ( just for kicks)
        for (int i = 0; i < allContours[winningIndex].size(); i++)
        {
            for (int j = 0; j < allContours[winningIndex].size(); j++)
            {
                if (allHierarchy[winningIndex][j][3] == winningParentId)
                {
                    double arclength = arcLength(allContours[winningIndex][j], false);
                    if (arclength > longestChildLength)
                    {
                        longestChildIndex = j;
                        longestChildLength = arclength;
                    }
                }
            }
        }





        Mat mask = Mat::zeros(thresholds[winningIndex].size(), CV_8U);

        // get rid of the outline by drawing a 1 pixel width black line
        drawContours(mask, allContours[winningIndex],
                     winningParentId, // draw this contour
                     cv::Scalar(255,255,255), // in
                     CV_FILLED,
                     8,
                     allHierarchy[winningIndex],
                     0
                    );


        // Morph Open the mask to get rid of any little connectors to non-plate portions
        int morph_elem  = 2;
        int morph_size = 3;
        Mat element = getStructuringElement( morph_elem, Size( 2*morph_size + 1, 2*morph_size+1 ), Point( morph_size, morph_size ) );

        //morphologyEx( mask, mask, MORPH_CLOSE, element );
        morphologyEx( mask, mask, MORPH_OPEN, element );

        //morph_size = 1;
        //element = getStructuringElement( morph_elem, Size( 2*morph_size + 1, 2*morph_size+1 ), Point( morph_size, morph_size ) );
        //dilate(mask, mask, element);


        // Drawing the edge black effectively erodes the image.  This may clip off some extra junk from the edges.
        // We'll want to do the contour again and find the larges one so that we remove the clipped portion.

        vector<vector<Point> > contoursSecondRound;

        findContours(mask, contoursSecondRound, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);
        int biggestContourIndex = -1;
        double largestArea = 0;
        for (int c = 0; c < contoursSecondRound.size(); c++)
        {
            double area = contourArea(contoursSecondRound[c]);
            if (area > largestArea)
            {
                biggestContourIndex = c;
                largestArea = area;
            }
        }

        if (biggestContourIndex != -1)
        {
            mask = Mat::zeros(thresholds[winningIndex].size(), CV_8U);

            vector<Point> smoothedMaskPoints;
            approxPolyDP(contoursSecondRound[biggestContourIndex], smoothedMaskPoints, 2, true);

            vector<vector<Point> > tempvec;
            tempvec.push_back(smoothedMaskPoints);
            //fillPoly(mask, smoothedMaskPoints.data(), smoothedMaskPoints, Scalar(255,255,255));
            drawContours(mask, tempvec,
                         0, // draw this contour
                         cv::Scalar(255,255,255), // in
                         CV_FILLED,
                         8,
                         allHierarchy[winningIndex],
                         0
                        );



        }

        if (this->config->debugCharAnalysis)
        {
            vector<Mat> debugImgs;
            Mat debugImgMasked = Mat::zeros(thresholds[winningIndex].size(), CV_8U);

            thresholds[winningIndex].copyTo(debugImgMasked, mask);

            debugImgs.push_back(mask);
            debugImgs.push_back(thresholds[winningIndex]);
            debugImgs.push_back(debugImgMasked);

            Mat dashboard = drawImageDashboard(debugImgs, CV_8U, 1);
            displayImage(config, "Winning outer box", dashboard);
        }

        hasPlateMask = true;
        return mask;
    }

    hasPlateMask = false;
    Mat fullMask = Mat::zeros(thresholds[0].size(), CV_8U);
    bitwise_not(fullMask, fullMask);
    return fullMask;



}
コード例 #2
0
ファイル: LP.cpp プロジェクト: wenqingchu/alignment_txt
bool LicensePlate::IsPossibleLPUsingCharFeature(Rect LPRect) {
	Mat ROI = LPRedChannel(LPRect).clone();
	medianBlur(ROI, ROI, 3);
	threshold(ROI, ROI, 0, 255, CV_THRESH_BINARY | CV_THRESH_OTSU);
	Mat RR = ROI.clone();
	Mat HClose = getStructuringElement(MORPH_CROSS, Size(45, 1));
	morphologyEx(RR, RR, MORPH_CLOSE, HClose);

	vector<int> ar;
	vector<Rect> rt;

	GetComponent(RR, ar, rt);
	int maxRectArea = 0, p = -1;
	for(int i = 0; i < ar.size(); i++) {
		if(maxRectArea < ar[i]) {
			maxRectArea = ar[i];
			p = i;
		}
	}
	assert(p != -1);
	LPRect.x += rt[p].x;
	LPRect.y += rt[p].y;
	LPRect.width = rt[p].width;
	LPRect.height = rt[p].height;

	ROI = ROI(rt[p]);

	int xHist[MAXC];
	memset(xHist, 0, sizeof(xHist));
	for(int r = 0; r < ROI.rows; r++)
		for(int c = 0; c < ROI.cols; c++) {
			if(ROI.at<uchar>(r, c)) xHist[c]++;
		}

	int N = ROI.cols;
	int rk[MAXC];
	memcpy(rk, xHist, sizeof(rk));
	sort(rk, rk + N);
	int bottomThreshold = 0;
	int topThreshold = 0;
	int percent = N / 3;
	for(int i = 0; i < percent; i++) {
		bottomThreshold += rk[i];
		topThreshold += rk[N - i - 1];
	}
	bottomThreshold /= percent;
	topThreshold /= percent;

	bottomThreshold = max(topThreshold / 10, bottomThreshold);
	bool isTop[MAXC];
	for(int i = 0; i < N; i++) {
		isTop[i] = (xHist[i] >= bottomThreshold);
	}
	Mat hist(1, ROI.cols, CV_8UC1);
	vector<pair<int, int> > interval, unionInterval;
	for(int i = 0; i < ROI.cols; i++) {
		hist.at<uchar>(0, i) = isTop[i];
		if(isTop[i]) interval.push_back(make_pair(i, i + 1));
	}
	int L, R = -100;
	for(int i = 0; i < interval.size(); i++) {
		int l = interval[i].first;
		int r = interval[i].second;
		if(l - R < 5) {
			R = r;
		} else {
			if(R != -100) unionInterval.push_back(make_pair(L, R));
			L = l, R = r;
		}
	}
	if(R != -100) unionInterval.push_back(make_pair(L, R));

	if(unionInterval.size() < 3 || unionInterval.size() > 10) return 0;

	return 1;
}
vector<Plate> DetectRegions::segment(Mat input){
    vector<Plate> output;

    //convert image to gray
    Mat img_gray;
    cvtColor(input, img_gray, CV_BGR2GRAY);
    blur(img_gray, img_gray, Size(5,5));

    //Finde vertical lines. Car plates have high density of vertical lines
    Mat img_sobel;
    Sobel(img_gray, img_sobel, CV_8U, 1, 0, 3, 1, 0, BORDER_DEFAULT);
    if(showSteps)
        imshow("Sobel", img_sobel);

    //threshold image
    Mat img_threshold;
    threshold(img_sobel, img_threshold, 0, 255, CV_THRESH_OTSU+CV_THRESH_BINARY);
    if(showSteps)
        imshow("Threshold", img_threshold);

    //Morphplogic operation close
    Mat element = getStructuringElement(MORPH_RECT, Size(17, 3) );
    morphologyEx(img_threshold, img_threshold, CV_MOP_CLOSE, element);
    if(showSteps)
        imshow("Close", img_threshold);

    //Find contours of possibles plates
    vector< vector< Point> > contours;
    findContours(img_threshold,
            contours, // a vector of contours
            CV_RETR_EXTERNAL, // retrieve the external contours
            CV_CHAIN_APPROX_NONE); // all pixels of each contours

    //Start to iterate to each contour founded
    vector<vector<Point> >::iterator itc= contours.begin();
    vector<RotatedRect> rects;

    //Remove patch that are no inside limits of aspect ratio and area.
    while (itc!=contours.end()) {
        //Create bounding rect of object
        RotatedRect mr= minAreaRect(Mat(*itc));
        if( !verifySizes(mr)){
            itc= contours.erase(itc);
        }else{
            ++itc;
            rects.push_back(mr);
        }
    }

    // Draw blue contours on a white image
    cv::Mat result;
    input.copyTo(result);
    cv::drawContours(result,contours,
            -1, // draw all contours
            cv::Scalar(255,0,0), // in blue
            1); // with a thickness of 1

    for(int i=0; i< (int)rects.size(); i++){

        //For better rect cropping for each posible box
        //Make floodfill algorithm because the plate has white background
        //And then we can retrieve more clearly the contour box
        circle(result, rects[i].center, 3, Scalar(0,255,0), -1);
        //get the min size between width and height
        float minSize=(rects[i].size.width < rects[i].size.height)?rects[i].size.width:rects[i].size.height;
        minSize=minSize-minSize*0.5;
        //initialize rand and get 5 points around center for floodfill algorithm
        //srand ( time(NULL) );
        //Initialize floodfill parameters and variables
        Mat mask;
        mask.create(input.rows + 2, input.cols + 2, CV_8UC1);
        mask= Scalar::all(0);
        int loDiff = 30;
        int upDiff = 30;
        int connectivity = 4;
        int newMaskVal = 255;
        int NumSeeds = 10;
        Rect ccomp;
        int flags = connectivity + (newMaskVal << 8 ) + CV_FLOODFILL_FIXED_RANGE + CV_FLOODFILL_MASK_ONLY;
        for(int j=0; j<NumSeeds; j++){
            Point seed;
            seed.x=rects[i].center.x+rand()%(int)minSize-(minSize/2);
            seed.y=rects[i].center.y+rand()%(int)minSize-(minSize/2);
            circle(result, seed, 1, Scalar(0,255,255), -1);
            floodFill(input, mask, seed, Scalar(255,0,0), &ccomp, Scalar(loDiff, loDiff, loDiff), Scalar(upDiff, upDiff, upDiff), flags);
        }
        if(showSteps)
            imshow("MASK", mask);
        //cvWaitKey(0);

        //Check new floodfill mask match for a correct patch.
        //Get all points detected for get Minimal rotated Rect
        vector<Point> pointsInterest;
        Mat_<uchar>::iterator itMask= mask.begin<uchar>();
        Mat_<uchar>::iterator end= mask.end<uchar>();
        for( ; itMask!=end; ++itMask)
            if(*itMask==255)
                pointsInterest.push_back(itMask.pos());

        RotatedRect minRect = minAreaRect(pointsInterest);

        if(verifySizes(minRect)){
            // rotated rectangle drawing
            Point2f rect_points[4]; minRect.points( rect_points );
            for( int j = 0; j < 4; j++ )
                line( result, rect_points[j], rect_points[(j+1)%4], Scalar(0,0,255), 1, 8 );

            //Get rotation matrix
            float r= (float)minRect.size.width / (float)minRect.size.height;
            float angle=minRect.angle;
            if(r<1)
                angle=90+angle;
            Mat rotmat= getRotationMatrix2D(minRect.center, angle,1);

            //Create and rotate image
            Mat img_rotated;
            warpAffine(input, img_rotated, rotmat, input.size(), CV_INTER_CUBIC);

            //Crop image
            Size rect_size=minRect.size;
            if(r < 1)
                swap(rect_size.width, rect_size.height);
            Mat img_crop;
            getRectSubPix(img_rotated, rect_size, minRect.center, img_crop);

            Mat resultResized;
            resultResized.create(33,144, CV_8UC3);
            resize(img_crop, resultResized, resultResized.size(), 0, 0, INTER_CUBIC);
            //Equalize croped image
            Mat grayResult;
            cvtColor(resultResized, grayResult, CV_BGR2GRAY);
            blur(grayResult, grayResult, Size(3,3));
            grayResult=histeq(grayResult);
            if(saveRegions){
                stringstream ss(stringstream::in | stringstream::out);
                ss << ".\\output\\possible_plates\\" << filename << "_" << i << ".JPG";
                imwrite(ss.str(), grayResult);
            }
            output.push_back(Plate(grayResult,minRect.boundingRect()));
        }
    }
    if(showSteps)
        imshow("Contours", result);

    return output;
}