MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    connect(ui->openButton, SIGNAL(clicked()), this, SLOT(OpenImage()));
    connect(ui->saveButton, SIGNAL(clicked()), this, SLOT(SaveImage()));
    connect(ui->saveDisplayButton, SIGNAL(clicked()), this, SLOT(SaveDisplayImage()));
    connect(ui->resetButton, SIGNAL(clicked()), this, SLOT(ResetImage()));
    connect(ui->toggleButton, SIGNAL(pressed()), this, SLOT(ToggleImage()));
    connect(ui->toggleButton, SIGNAL(released()), this, SLOT(ToggleImage()));

    connect(ui->bwButton, SIGNAL(clicked()), this, SLOT(BlackWhiteImage()));
    connect(ui->noiseButton, SIGNAL(clicked()), this, SLOT(AddNoise()));
    connect(ui->meanButton, SIGNAL(clicked()), this, SLOT(MeanBlurImage()));
    connect(ui->medianButton, SIGNAL(clicked()), this, SLOT(MedianImage()));
    connect(ui->gaussianBlurButton, SIGNAL(clicked()), this, SLOT(GaussianBlurImage()));
    connect(ui->firstDerivButton, SIGNAL(clicked()), this, SLOT(FirstDerivImage()));
    connect(ui->secondDerivButton, SIGNAL(clicked()), this, SLOT(SecondDerivImage()));
    connect(ui->sharpenButton, SIGNAL(clicked()), this, SLOT(SharpenImage()));
    connect(ui->sobelButton, SIGNAL(clicked()), this, SLOT(SobelImage()));
    connect(ui->bilateralButton, SIGNAL(clicked()), this, SLOT(BilateralImage()));
    connect(ui->halfButton, SIGNAL(clicked()), this, SLOT(HalfImage()));
    connect(ui->rotateButton, SIGNAL(clicked()), this, SLOT(RotateImage()));
    connect(ui->peaksButton, SIGNAL(clicked()), this, SLOT(FindPeaksImage()));
    connect(ui->houghButton, SIGNAL(clicked()), this, SLOT(HoughImage()));
    connect(ui->crazyButton, SIGNAL(clicked()), this, SLOT(CrazyImage()));
    connect(ui->randomButton, SIGNAL(clicked()), this, SLOT(RandomSeedImage()));
    connect(ui->pixelButton, SIGNAL(clicked()), this, SLOT(PixelSeedImage()));
    connect(ui->histogramButton, SIGNAL(clicked()), this, SLOT(HistogramSeedImage()));

    connect(ui->actionOpen, SIGNAL(triggered()), this, SLOT(OpenImage()));
    connect(ui->zoomSlider, SIGNAL(valueChanged(int)), this, SLOT(Zoom(int)));
    connect(ui->brightnessSlider, SIGNAL(valueChanged(int)), this, SLOT(Brightness(int)));
    connect(ui->verticalScrollBar, SIGNAL(valueChanged(int)), this, SLOT(Scroll(int)));
    connect(ui->horizontalScrollBar, SIGNAL(valueChanged(int)), this, SLOT(Scroll(int)));

    ui->meanBox->setValue(2);
    ui->medianBox->setValue(2);
    ui->blurSpinBox->setValue(2.0);
    ui->firstDerivSpinBox->setValue(2.0);
    ui->secondDerivSpinBox->setValue(2.0);
    ui->sharpenSigmaSpinBox->setValue(2.0);
    ui->sharpenMagSpinBox->setValue(1.0);
    ui->bilateralSigmaSSpinBox->setValue(2.0);
    ui->bilateralSigmaISpinBox->setValue(20.0);
    ui->noiseSpinBox->setValue(10.0);
    ui->orientationSpinBox->setValue(10.0);
    ui->peakThresholdSpinBox->setValue(10.0);
    ui->colorNoiseCheckBox->setChecked(true);
    ui->zoomSlider->setValue(0);
    ui->brightnessSlider->setValue(0);
    ui->clusterBox->setValue(4);

    displayImage = QImage(ui->ImgDisplay->width(), ui->ImgDisplay->height(), QImage::Format_RGB32);
}
void MainWindow::SharpenImage()
{
    double sigma = ui->sharpenSigmaSpinBox->value();
    double mag = ui->sharpenMagSpinBox->value();

    SharpenImage(&outImage, sigma, mag);

    DrawDisplayImage();
}
cv::Mat CorrectPerspective::UpdatePerspective(cv::Mat source, bool sharpenImage)
{
	cv::Point2f sourceImageSize(source.cols, source.rows);

	cv::Mat sourceImageCpy(cv::Size(sourceImageSize.x * 2, sourceImageSize.y * 2), CV_8UC3, cv::Scalar(0, 0, 0));

	cv::Mat dst = sourceImageCpy(cv::Rect(sourceImageSize.x / 2,
		sourceImageSize.y / 2,
		sourceImageSize.x,
		sourceImageSize.y
		));
	source.copyTo(dst);

	cv::Rect boundRect = boundingRect(m_points);

	std::vector<cv::Point2f> outputPoint;
	outputPoint.push_back(cv::Point2f(boundRect.x, boundRect.y));
	outputPoint.push_back(cv::Point2f(boundRect.x, boundRect.y + boundRect.height));
	outputPoint.push_back(cv::Point2f(boundRect.x + boundRect.width, boundRect.y));
	outputPoint.push_back(cv::Point2f(boundRect.x + boundRect.width, boundRect.y + boundRect.height));

	cv::Mat transformMatrix = cv::getPerspectiveTransform(m_points, outputPoint);
	cv::Mat transformed = cv::Mat::zeros(sourceImageCpy.rows, sourceImageCpy.cols, CV_8UC3);

	//cv::warpPerspective(sourceImageCpy, transformed, transformMatrix, sourceImageCpy.size());
	
	if (!m_calculated)
	{
		// Since the camera won't be moving, let's pregenerate the remap LUT
		cv::Mat inverseTransMatrix;
		cv::invert(transformMatrix, inverseTransMatrix);

		// Generate the warp matrix
		cv::Mat map_x, map_y, srcTM;
		srcTM = inverseTransMatrix.clone(); // If WARP_INVERSE, set srcTM to transformationMatrix

		map_x.create(sourceImageCpy.size(), CV_32FC1);
		map_y.create(sourceImageCpy.size(), CV_32FC1);

		double M11, M12, M13, M21, M22, M23, M31, M32, M33;
		M11 = srcTM.at<double>(0, 0);
		M12 = srcTM.at<double>(0, 1);
		M13 = srcTM.at<double>(0, 2);
		M21 = srcTM.at<double>(1, 0);
		M22 = srcTM.at<double>(1, 1);
		M23 = srcTM.at<double>(1, 2);
		M31 = srcTM.at<double>(2, 0);
		M32 = srcTM.at<double>(2, 1);
		M33 = srcTM.at<double>(2, 2);

		for (int y = 0; y < sourceImageCpy.rows; y++) {
			double fy = (double)y;
			for (int x = 0; x < sourceImageCpy.cols; x++) {
				double fx = (double)x;
				double w = ((M31 * fx) + (M32 * fy) + M33);
				w = w != 0.0f ? 1.f / w : 0.0f;
				float new_x = (float)((M11 * fx) + (M12 * fy) + M13) * w;
				float new_y = (float)((M21 * fx) + (M22 * fy) + M23) * w;
				map_x.at<float>(y, x) = new_x;
				map_y.at<float>(y, x) = new_y;
			}
		}

		// This creates a fixed-point representation of the mapping resulting in ~4% CPU savings

		transformation_x.create(sourceImageCpy.size(), CV_16SC2);
		transformation_y.create(sourceImageCpy.size(), CV_16UC1);

		cv::convertMaps(map_x, map_y, transformation_x, transformation_y, false);
		m_calculated = true;
	}
	// If the fixed-point representation causes issues, replace it with this code
	//transformation_x = map_x.clone();
	//transformation_y = map_y.clone();

	
	cv::remap(sourceImageCpy, transformed, transformation_x, transformation_y, CV_INTER_LINEAR);
	
	
	//Utils::GetTime(true);

	//rectangle(transformed, boundRect, cv::Scalar(0, 255, 0), 1, 8, 0);

	
	if (boundRect.x < 0)
	{
		boundRect.width += boundRect.x;
		boundRect.x = 0;
	}
	if (boundRect.width + boundRect.x > transformed.cols)
	{
		boundRect.width = transformed.cols - boundRect.x;
	}
	if (boundRect.y < 0)
	{
		boundRect.height += boundRect.y;
		boundRect.y = 0;
	}
	if (boundRect.height + boundRect.y > transformed.rows)
	{
		boundRect.height = transformed.rows - boundRect.y;
	}

	transformed = transformed(boundRect);

	if (sharpenImage)
	{
		transformed = SharpenImage(transformed);
	}

	m_currentImage = transformed.clone();

	return transformed;
}