int main(void) {

    cv::Mat imgBlank(700, 900, CV_8UC3, cv::Scalar::all(0));            // declare a blank image for moving the mouse over

    std::vector<cv::Point> mousePositions;

    cv::Point predictedMousePosition;

    cv::namedWindow("imgBlank");                                // declare window
    cv::setMouseCallback("imgBlank", mouseMoveCallback);        // 

    while (true) {

        mousePositions.push_back(mousePosition);            // get the current position

        predictedMousePosition = predictNextPosition(mousePositions);        // predict the next position

        std::cout << "current position        = " << mousePositions.back().x << ", " << mousePositions.back().y << "\n";
        std::cout << "next predicted position = " << predictedMousePosition.x << ", " << predictedMousePosition.y << "\n";
        std::cout << "--------------------------------------------------\n";

        drawCross(imgBlank, mousePositions.back(), SCALAR_WHITE);
        drawCross(imgBlank, predictedMousePosition, SCALAR_BLUE);                      // draw a cross at the most recent predicted, actual, and corrected positions

        cv::imshow("imgBlank", imgBlank);         // show the image

        cv::waitKey(10);                    // pause for a moment to get operating system to redraw the imgBlank

        imgBlank = cv::Scalar::all(0);         // blank the imgBlank for next time around
    }

    return 0;
}
void CCaptchaGenerator::ReGenerateCaptcha(uint32 nLetterCount)
{
	Clear();
	CxImage* pimgResult = new CxImage(nLetterCount > 1 ? (LETTERSIZE + (nLetterCount-1)*CROWDEDSIZE) : LETTERSIZE, 32, 1, CXIMAGE_FORMAT_BMP);
	pimgResult->SetPaletteColor(0, 255, 255, 255);
	pimgResult->SetPaletteColor(1, 0, 0, 0, 0);
	pimgResult->Clear();
	CxImage imgBlank(LETTERSIZE, LETTERSIZE, 1, CXIMAGE_FORMAT_BMP);	
	imgBlank.SetPaletteColor(0, 255, 255, 255);
	imgBlank.SetPaletteColor(1, 0, 0, 0, 0);
	imgBlank.Clear();
	for (uint32 i = 0; i < nLetterCount; i++) {
		CxImage imgLetter(imgBlank);
		
		CString strLetter(schCaptchaContent[GetRandomUInt16() % ARRSIZE(schCaptchaContent)]);
		m_strCaptchaText += strLetter;
		
		uint16 nRandomSize = GetRandomUInt16() % 10;
		uint16 nRandomOffset = 3 + GetRandomUInt16() % 11;
		imgLetter.DrawString(NULL, nRandomOffset, 32, strLetter, imgLetter.RGBtoRGBQUAD(RGB(0, 0, 0)), _T("Arial"), 40 - nRandomSize, 1000);
		//imgLetter.DrawTextA(NULL, nRandomOffset, 32, strLetter, imgLetter.RGBtoRGBQUAD(RGB(0, 0, 0)), "Arial", 40 - nRandomSize, 1000);
		float fRotate = (float)(35 - (GetRandomUInt16() % 70));
		imgLetter.Rotate2(fRotate, NULL, CxImage::IM_BILINEAR,  CxImage::OM_BACKGROUND, 0, false, true);
		uint32 nOffset = i * CROWDEDSIZE; 
		ASSERT( imgLetter.GetHeight() == pimgResult->GetHeight() && pimgResult->GetWidth() >= nOffset + imgLetter.GetWidth() );
		for (uint32 j = 0; j < imgLetter.GetHeight(); j++)
			for (uint32 k = 0; k < imgLetter.GetWidth(); k++)
				if (pimgResult->GetPixelIndex(nOffset + k, j) != 1)
					pimgResult->SetPixelIndex(nOffset + k, j, imgLetter.GetPixelIndex(k, j));
	}
	pimgResult->Jitter(1);
	//pimgResult->Save("D:\\CaptchaTest.bmp", CXIMAGE_FORMAT_BMP);
	m_pimgCaptcha = pimgResult;
}
int main(void) {

    cv::KalmanFilter kalmanFilter(4, 2, 0);                             // instantiate Kalman Filter

    float fltTransitionMatrixValues[4][4] = { { 1, 0, 1, 0 },           // declare an array of floats to feed into Kalman Filter Transition Matrix, also known as State Transition Model
                                              { 0, 1, 0, 1 },
                                              { 0, 0, 1, 0 },
                                              { 0, 0, 0, 1 } };
    
    kalmanFilter.transitionMatrix = cv::Mat(4, 4, CV_32F, fltTransitionMatrixValues);       // set Transition Matrix

    float fltMeasurementMatrixValues[2][4] = { { 1, 0, 0, 0 },          // declare an array of floats to feed into Kalman Filter Measurement Matrix, also known as Measurement Model
                                               { 0, 1, 0, 0 } };

    kalmanFilter.measurementMatrix = cv::Mat(2, 4, CV_32F, fltMeasurementMatrixValues);     // set Measurement Matrix

    cv::setIdentity(kalmanFilter.processNoiseCov, cv::Scalar::all(0.0001));           // default is 1, for smoothing try 0.0001
    cv::setIdentity(kalmanFilter.measurementNoiseCov, cv::Scalar::all(10));         // default is 1, for smoothing try 10
    cv::setIdentity(kalmanFilter.errorCovPost, cv::Scalar::all(0.1));               // default is 0, for smoothing try 0.1

    cv::Mat imgBlank(700, 900, CV_8UC3, cv::Scalar::all(0));            // declare a blank image for moving the mouse over

    std::vector<cv::Point> predictedMousePositions;                 // declare 3 vectors for predicted, actual, and corrected positions
    std::vector<cv::Point> actualMousePositions;
    std::vector<cv::Point> correctedMousePositions;

    cv::namedWindow("imgBlank");                                // declare window
    cv::setMouseCallback("imgBlank", mouseMoveCallback);        // 

    while (true) {
        cv::Mat matPredicted = kalmanFilter.predict();

        cv::Point ptPredicted((int)matPredicted.at<float>(0), (int)matPredicted.at<float>(1));

        cv::Mat matActualMousePosition(2, 1, CV_32F, cv::Scalar::all(0));

        matActualMousePosition.at<float>(0, 0) = (float)ptActualMousePosition.x;
        matActualMousePosition.at<float>(1, 0) = (float)ptActualMousePosition.y;

        cv::Mat matCorrected = kalmanFilter.correct(matActualMousePosition);        // function correct() updates the predicted state from the measurement

        cv::Point ptCorrected((int)matCorrected.at<float>(0), (int)matCorrected.at<float>(1));

        predictedMousePositions.push_back(ptPredicted);
        actualMousePositions.push_back(ptActualMousePosition);
        correctedMousePositions.push_back(ptCorrected);

            // predicted, actual, and corrected are all now calculated, time to draw stuff

        drawCross(imgBlank, ptPredicted, SCALAR_BLUE);                      // draw a cross at the most recent predicted, actual, and corrected positions
        drawCross(imgBlank, ptActualMousePosition, SCALAR_WHITE);
        drawCross(imgBlank, ptCorrected, SCALAR_GREEN);
        
        for (int i = 0; i < predictedMousePositions.size() - 1; i++) {                  // draw each predicted point in blue
            cv::line(imgBlank, predictedMousePositions[i], predictedMousePositions[i + 1], SCALAR_BLUE, 1);
        }

        for (int i = 0; i < actualMousePositions.size() - 1; i++) {                     // draw each actual point in white
            cv::line(imgBlank, actualMousePositions[i], actualMousePositions[i + 1], SCALAR_WHITE, 1);
        }

        for (int i = 0; i < correctedMousePositions.size() - 1; i++) {                  // draw each corrected point in green
            cv::line(imgBlank, correctedMousePositions[i], correctedMousePositions[i + 1], SCALAR_GREEN, 1);
        }

        cv::imshow("imgBlank", imgBlank);         // show the image
        
        cv::waitKey(10);                    // pause for a moment to get operating system to redraw the imgBlank

        imgBlank = cv::Scalar::all(0);         // blank the imgBlank for next time around
    }

    return 0;
}