GBL::CmRetCode_t Utils::drawHelper(OutputMethod::OutputMethodFrameInterface& outputMethod, InputMethod::InputMethodInterface& inputMethod, Draw::DrawInterface& drawer, const ImageProc::ImageProc& imProc, std::vector<GBL::DescriptorContainer_t> descriptors, std::vector<GBL::MatchesContainer_t> allMatches, uint32_t nbFrames, DrawResultProc_f procFunction, const GBL::Image_t* const image2) {
			LOG_ENTER("Drawing files");
			GBL::Frame_t preFrame1;
			GBL::Frame_t frame1;
			if (inputMethod.getFrame(0, preFrame1) != GBL::RESULT_SUCCESS) {
				LOG_ERROR("Could not get frame %d", 0);
			}
			if(procFunction != nullptr) {
				procFunction(imProc, preFrame1, *image2, frame1);
			} else {
				frame1 = preFrame1;
			}
			for (uint32_t j = 0; j < nbFrames-1; j++) {
				LOG_INFO("Generating frame %d", j+1);
				GBL::Frame_t preFrame2;
				// Index of getFrame should compensate for first background image
				if (inputMethod.getFrame(j+2, preFrame2) != GBL::RESULT_SUCCESS) {
					LOG_ERROR("Could not get frame %d", j+1);
					continue;
				}

				GBL::Image_t frame2;
				if(procFunction != nullptr && image2 != nullptr) {
					procFunction(imProc, preFrame2, *image2, frame2);
				} else {
					frame2 = preFrame2;
				}
				if(allMatches[j].valid == true) {
					GBL::Image_t outputFrame;
					drawer.draw(frame1, frame2, allMatches[j].matches, descriptors[j].keypoints, descriptors[j + 1].keypoints, outputFrame);
					outputMethod.write(outputFrame);
				}
				frame1 = frame2;
			}
			drawer.closeFile();
			return GBL::RESULT_SUCCESS;
		}
std::vector<GBL::Displacement_t> findTheBallPipeline(const char* const videoFile, const ImageProc::ImageProc* imProc, Draw::DrawInterface& drawer,
		const Detector::DetectorInterface& detectorInterface, const Descriptor::DescriptorInterface& descriptorInterface, const Match::MatcherInterface& matcherInterface, const Displacement::DisplacementInterface& displacementInterface,
		InputMethod::InputMethodInterface& inputMethodInterface, OutputMethod::OutputMethodInterface& outputMethodInterface) {
	
	// Single threaded initialization phase
	if (inputMethodInterface.start(videoFile) != GBL::RESULT_SUCCESS) {
		LOG_ERROR("Could not open %s", videoFile);
		return std::vector < GBL::Displacement_t > (0);
	}

	// Open our own output interface in case we want to draw
	OutputMethod::OutputImageSequence* outImSeq = nullptr;
	if(GBL::drawResults_b) {
		outImSeq = new OutputMethod::OutputImageSequence();
		outImSeq->open("correspondence_frame");
	}

	// Get background image
	GBL::Frame_t background;
	LOG_INFO("Retrieving background");
	// For now take first frame as the background
	if (inputMethodInterface.getNextFrame(background) != GBL::RESULT_SUCCESS) {
		LOG_ERROR("Could not get background");
		return std::vector < GBL::Displacement_t > (0);
	}

	const uint32_t nbFrames = 50;
	GBL::DescriptorContainer_t descriptors[nbFrames];
	std::vector<GBL::Displacement_t> displacements(nbFrames);

	LOG_INFO("Processing frames");
	GBL::Frame_t* frame = new GBL::Frame_t;
	uint32_t i = 0;
	uint32_t sequenceNo = 0;
#pragma omp parallel shared(inputMethodInterface, detectorInterface, descriptorInterface, matcherInterface, displacementInterface, outputMethodInterface, background, displacements, descriptors, imProc, frame, i, sequenceNo, outImSeq)
{	

	#pragma omp single nowait
	while(inputMethodInterface.isMoreInput()) {
		if(inputMethodInterface.getNextFrame(*frame) != GBL::RESULT_SUCCESS) {
			// Lets assume max 30 fps and put the thread to sleep for a while
			usleep(20000);
			continue;
		}
		#pragma omp task firstprivate(i, frame, sequenceNo) shared(descriptors, detectorInterface, descriptorInterface, matcherInterface, displacements, displacementInterface, outputMethodInterface, imProc, background, outImSeq) 
		{
			// Description
			LOG_ENTER("Describing image %d", i); 
			descriptors[i].sequenceNo = sequenceNo;
			descriptionHelper(*frame, descriptors[i], background, detectorInterface, descriptorInterface, *imProc);

			// Check whether neighbours still exist
			uint32_t prevNeighbourIndex = (i+nbFrames-1) % nbFrames;
			if(descriptors[prevNeighbourIndex].sequenceNo == sequenceNo-1) {
				// Check neighbours whether they are ready
				if(descriptors[prevNeighbourIndex].ready == true) {
					LOG_INFO("Matching %d and %d", prevNeighbourIndex, i);
					GBL::MatchesContainer_t matches;
					matcherHelper(descriptors[prevNeighbourIndex], descriptors[i], matches, matcherInterface);
					LOG_INFO("Calculating displacement of %d and %d", prevNeighbourIndex, i);
					displacements[prevNeighbourIndex].sequenceNo = sequenceNo - 1;
					displacementHelper(descriptors[prevNeighbourIndex], descriptors[i], matches, displacements[prevNeighbourIndex], displacementInterface, outputMethodInterface);

					if (GBL::drawResults_b || GBL::showStuff_b) {
						GBL::Frame_t prevNeighbourFrame;
						LOG_INFO("Generating corresponding frame %d and %d", prevNeighbourIndex, i);
						// For the index of getFrame we need to add the background frame again
						if(inputMethodInterface.getFrame(sequenceNo, prevNeighbourFrame) == GBL::RESULT_SUCCESS) {
							Utils::Utils::drawResult(prevNeighbourFrame, *frame, drawer, descriptors[prevNeighbourIndex], descriptors[i], matches, outImSeq);	
						} else {
							LOG_WARNING("Could not get frame of neighbour");
						}
					}
				}
			} else {
				LOG_WARNING("Previous neighbour was someone else");
			}
			uint32_t nextNeighbourIndex = (i+1) % nbFrames;
			if(descriptors[nextNeighbourIndex].sequenceNo == sequenceNo+1) {
				if(descriptors[nextNeighbourIndex].ready == true) {
					LOG_INFO("Matching %d and %d", i, nextNeighbourIndex);
					GBL::MatchesContainer_t matches;
					matcherHelper(descriptors[i], descriptors[nextNeighbourIndex], matches, matcherInterface);
					LOG_INFO("Calculating displacement of %d and %d", i, nextNeighbourIndex);
					displacements[i].sequenceNo = sequenceNo;
					displacementHelper(descriptors[i], descriptors[nextNeighbourIndex], matches, displacements[i], displacementInterface, outputMethodInterface);
				}
			} else {
				LOG_WARNING("Next neighbour was someone else");
			}
			delete frame;
		}
		sequenceNo++;
		i = (i+1) % nbFrames;
		// Reset the i-th buffers
		descriptors[i].valid = false;
		descriptors[i].ready = false;
		descriptors[i].keypoints.clear();
		frame = new GBL::Frame_t;
	}
}
	if(GBL::drawResults_b) {
		outImSeq->close();
	}
	inputMethodInterface.stop();
	delete frame;
	return displacements;
}