ci::Channel8uRef AdaptiveThresholdBinarization::process( ci::Channel8uRef surface )
{
	/*
	(Brief) How this algorithm works:

	Based on: Pierre D. Wellner. Adaptive thresholding for the digitaldesk. Technical Report EPC-1993-110, Rank Xerox Research Centre, Cambridge Laboratory, 61 Regent Street, Cambridge CB2 1AB, 1993.

	The threshold estimate starts at 0. At every pixel, the threshold is re-evaluated with the current pixel
	added as value, and an estimate of the dropped pixel subtracted (to save memory). Each evaluation is then an
	average of "all the pixel values in the window" (+ the values of the last row averaged together)
	divided by the pixel window, and then "lessened by the threshold". This value then helps determine if the next pixel
	should be considered foreground or background.
	*/

	mBinaPixelWindowEstimate = 0;
	mBinaThreshold = 0;
	std::memset( mBinaPrevRowThresholdEstimate.get(), 0, kmIncomingImgsWidth ); // Not super necessary

	mImageProcessed = surface;
	auto surfaceIter = mImageProcessed->getIter();

	// Draw border
	while ( surfaceIter.line() )
	{
		if ( surfaceIter.y() % 2 )
		{
			// Even Rows
			while ( surfaceIter.pixel() )
			{
				processPixel( surfaceIter );
			}
		}
		else {
			// Un-even rows

			// Cinder doesn't support reverse iteration so we'll have to work a little internal-pointer majik here.
			// Set interal pixel pointer to last pixel on row
			surfaceIter.pixel();
			surfaceIter.mPtr += ( surfaceIter.mWidth - 1 ) * surfaceIter.mInc;
			surfaceIter.mX += surfaceIter.mEndX - 1;

			while ( surfaceIter.mX >= surfaceIter.mStartX )
			{
				processPixel( surfaceIter );

				surfaceIter.mPtr -= surfaceIter.mInc;
				--surfaceIter.mX;
			}
		}
	}

	return mImageProcessed;
}
cv::Mat IteratePixelEffect::process(cv::Mat in) {
	cv::Mat altered = in.clone();
	for (int row = 0; row < in.rows; row++ ) {
		for(int col = 0; col < in.cols; col++ ) {
			altered.at<cv::Vec3b>(row, col) = processPixel(in.at<cv::Vec3b>(row, col), row, col);
		}
	}
	return altered;
}
void LaserDetectionHSVRunner::run() {
	int w = image.width();

	bool leftFound = false;
	int leftFoundGreen;
	int leftFoundX = 0;

	bool rightFound = false;
	int rightFoundGreen;
	int rightFoundX = 0;

	for (int x = 0; x < w; x++) {
		scanLine[x] = processPixel(x, workingY);

//		int g = qGreen(scanLine[x]);
//
//		if (scanLine[x] == qRgb(0, 0, 0)) {
//			continue;
//		}
//
//		if (x < w / 2) {
//			// left side
//			if (leftFound == false || leftFoundGreen < g) {
//				if (leftFound == true) {
//					scanLine[leftFoundX] = qRgb(0, 0, 0);
//				}
//
//				leftFoundX = x;
//				leftFoundGreen = g;
//				leftFound = true;
//
//				scanLine[leftFoundX] = qRgb(0, 255, 0);
//			} else {
//				scanLine[x] = qRgb(0, 0, 0);
//			}
//		} else {
//			// right side
//			if (rightFound == false || rightFoundGreen < g) {
//				if (rightFound == true) {
//					scanLine[rightFoundX] = qRgb(0, 0, 0);
//				}
//
//				rightFoundX = x;
//				rightFoundGreen = g;
//				rightFound = true;
//
//				scanLine[rightFoundX] = qRgb(0, 255, 0);
//			} else {
//				scanLine[x] = qRgb(0, 0, 0);
//			}
//		}
	}

}
void RowBitmapLineSegmentFinder::nextRow(uint8_t rowIndex, uint8_t bitmapHigh, uint8_t bitmapLow) {
  currentRowIndex = rowIndex;
  firstLineSegmentPreviousRow = firstLineSegment;
  secondLineSegmentPreviousRow = secondLineSegment;
  firstLineSegment = LineSegment();
  secondLineSegment = LineSegment();

  int8_t segmentStart = LineSegment::lineNotFound;
  if (rowIndex >= ignoreRows) {
    processPixel(bitmapLow  & (uint8_t)0b00000001,  0, segmentStart);
    processPixel(bitmapLow  & (uint8_t)0b00000010,  2, segmentStart);
    processPixel(bitmapLow  & (uint8_t)0b00000100,  4, segmentStart);
    processPixel(bitmapLow  & (uint8_t)0b00001000,  6, segmentStart);
    processPixel(bitmapLow  & (uint8_t)0b00010000,  8, segmentStart);
    processPixel(bitmapLow  & (uint8_t)0b00100000, 10, segmentStart);
    processPixel(bitmapLow  & (uint8_t)0b01000000, 12, segmentStart);
    processPixel(bitmapLow  & (uint8_t)0b10000000, 14, segmentStart);
    processPixel(bitmapHigh & (uint8_t)0b00000001, 16, segmentStart);
    processPixel(bitmapHigh & (uint8_t)0b00000010, 18, segmentStart);
    processPixel(bitmapHigh & (uint8_t)0b00000100, 20, segmentStart);
    processPixel(bitmapHigh & (uint8_t)0b00001000, 22, segmentStart);
    processPixel(bitmapHigh & (uint8_t)0b00010000, 24, segmentStart);
    processPixel(bitmapHigh & (uint8_t)0b00100000, 26, segmentStart);
    processPixel(bitmapHigh & (uint8_t)0b01000000, 28, segmentStart);
    processPixel(bitmapHigh & (uint8_t)0b10000000, 30, segmentStart);

    if (segmentStart != LineSegment::lineNotFound) {
      processLineSegment(segmentStart, 30);
    }
  }
};