const std::vector<unsigned char> &chilitags::ReadBits::operator()(const cv::Mat &inputImage, const Quad &corners) { cv::Mat_<cv::Point2f> cornersCopy(corners); auto roi = cv::boundingRect(cornersCopy); // Refine can actually provide corners outside the image roi.x = cv::max(roi.x, 0); roi.y = cv::max(roi.y, 0); roi.width = cv::min(roi.width, inputImage.cols-roi.x); roi.height = cv::min(roi.height, inputImage.rows-roi.y); cv::Point2f origin = roi.tl(); for (int i : {0,1,2,3}) cornersCopy(i) -= origin; cv::Matx33f transformation = cv::getPerspectiveTransform(NORMALIZED_CORNERS, cornersCopy); cv::perspectiveTransform(mSamplePoints, mTransformedSamplePoints, transformation); cv::Mat inputRoi = inputImage(roi); uchar* sampleData = mSamples.ptr(0); for (auto& transformedSamplePoint : mTransformedSamplePoints) { *sampleData++ = inputRoi.at<uchar>(transformedSamplePoint); } cv::threshold(mSamples, mBits, -1, 1, cv::THRESH_BINARY | cv::THRESH_OTSU); #ifdef DEBUG_ReadBits for (int i = 0; i < DATA_SIZE; ++i) { for (int j = 0; j < DATA_SIZE; ++j) { std::cout << (int) mBits[i*DATA_SIZE + j]; } std::cout << "\n"; } std::cout << std::endl; #define ZOOM_FACTOR 10 cv::Mat debugImage = inputImage.clone(); cv::Mat tag; cv::resize(inputRoi, tag, cv::Size(0,0), ZOOM_FACTOR, ZOOM_FACTOR, cv::INTER_NEAREST); cv::cvtColor(tag, tag, cv::COLOR_GRAY2BGR); for (int i = 0; i < DATA_SIZE; ++i) { for (int j = 0; j < DATA_SIZE; ++j) { cv::Point2f position = mTransformedSamplePoints[i*DATA_SIZE + j]; cv::circle(tag, position * ZOOM_FACTOR, 1, cv::Scalar(0,255,0),2); cv::circle(tag, position * ZOOM_FACTOR, 3, cv::Scalar::all(mBits[i*DATA_SIZE + j]*255),2); } } cv::circle(tag, *cornersCopy[0] * ZOOM_FACTOR, 3, cv::Scalar(255,0,0),2); cv::line(tag, *cornersCopy[0]*ZOOM_FACTOR, *cornersCopy[1]*ZOOM_FACTOR,cv::Scalar(255,0,0)); cv::line(tag, *cornersCopy[1]*ZOOM_FACTOR, *cornersCopy[2]*ZOOM_FACTOR,cv::Scalar(255,0,255)); cv::line(tag, *cornersCopy[2]*ZOOM_FACTOR, *cornersCopy[3]*ZOOM_FACTOR,cv::Scalar(255,0,255)); cv::line(tag, *cornersCopy[3]*ZOOM_FACTOR, *cornersCopy[0]*ZOOM_FACTOR,cv::Scalar(255,0,255)); cv::line(tag, *cornersCopy[2]*ZOOM_FACTOR, *cornersCopy[0]*ZOOM_FACTOR,cv::Scalar(255,0,255)); cv::line(tag, *cornersCopy[3]*ZOOM_FACTOR, *cornersCopy[1]*ZOOM_FACTOR,cv::Scalar(255,0,255)); cv::line(debugImage, *cornersCopy[0]+origin, *cornersCopy[1]+origin,cv::Scalar(255,0,255)); cv::line(debugImage, *cornersCopy[1]+origin, *cornersCopy[2]+origin,cv::Scalar(255,0,255)); cv::line(debugImage, *cornersCopy[2]+origin, *cornersCopy[3]+origin,cv::Scalar(255,0,255)); cv::line(debugImage, *cornersCopy[3]+origin, *cornersCopy[0]+origin,cv::Scalar(255,0,255)); cv::imshow("ReadBits-full", debugImage); cv::imshow("ReadBits-tag", tag); cv::waitKey(0); #endif return mBits; }
const std::vector<unsigned char>& ReadBits::operator()(const cv::Mat &inputImage, const Quad &corners) { static const float TAG_SIZE = 2*TAG_MARGIN+DATA_SIZE; static const Quad NORMALIZED_CORNERS = { 0.f, 0.f, TAG_SIZE, 0.f, TAG_SIZE, TAG_SIZE, 0.f, TAG_SIZE }; cv::Mat_<cv::Point2f> cornersCopy(corners); // Sometimes, the corners are refined into a concave quadrilateral // which makes ReadBits crash cv::Mat convexHull; cv::convexHull(cornersCopy, convexHull, true); if (convexHull.rows != 4) { cornersCopy = convexHull; cornersCopy.push_back(0.5f*(cornersCopy(0)+cornersCopy(1))); } auto roi = cv::boundingRect(cornersCopy); // Refine can actually provide corners outside the image roi.x = cv::max(roi.x, 0); roi.y = cv::max(roi.y, 0); roi.width = cv::min(roi.width, inputImage.cols-roi.x); roi.height = cv::min(roi.height, inputImage.rows-roi.y); cv::Point2f origin = roi.tl(); for (int i : {0,1,2,3}) cornersCopy(i) -= origin; cv::Matx33f transformation = cv::getPerspectiveTransform(NORMALIZED_CORNERS, cornersCopy); cv::perspectiveTransform(mSamplePoints, mTransformedSamplePoints, transformation); cv::Mat inputRoi = inputImage(roi); uchar* sampleData = mSamples.ptr(0); for (auto& transformedSamplePoint : mTransformedSamplePoints) { transformedSamplePoint.x = cv::max(cv::min(roi.width - 1, (int)std::round(transformedSamplePoint.x)), 0); transformedSamplePoint.y = cv::max(cv::min(roi.height - 1, (int)std::round(transformedSamplePoint.y)), 0); *sampleData++ = inputRoi.at<uchar>(transformedSamplePoint); } cv::threshold(mSamples, mBits, -1, 1, cv::THRESH_BINARY | cv::THRESH_OTSU); #ifdef DEBUG_ReadBits for (int i = 0; i < DATA_SIZE; ++i) { for (int j = 0; j < DATA_SIZE; ++j) { std::cout << (int) mBits[i*DATA_SIZE + j]; } std::cout << "\n"; } std::cout << std::endl; #define ZOOM_FACTOR 10 cv::Mat debugImage = inputImage.clone(); cv::Mat tag; cv::resize(inputRoi, tag, cv::Size(0,0), ZOOM_FACTOR, ZOOM_FACTOR, cv::INTER_NEAREST); cv::cvtColor(tag, tag, cv::COLOR_GRAY2BGR); for (int i = 0; i < DATA_SIZE; ++i) { for (int j = 0; j < DATA_SIZE; ++j) { cv::Point2f position = mTransformedSamplePoints[i*DATA_SIZE + j]; cv::circle(tag, position * ZOOM_FACTOR, 1, cv::Scalar(0,255,0),2); cv::circle(tag, position * ZOOM_FACTOR, 3, cv::Scalar::all(mBits[i*DATA_SIZE + j]*255),2); } } cv::circle(tag, *cornersCopy[0] * ZOOM_FACTOR, 3, cv::Scalar(255,0,0),2); cv::line(tag, *cornersCopy[0]*ZOOM_FACTOR, *cornersCopy[1]*ZOOM_FACTOR,cv::Scalar(255,0,0)); cv::line(tag, *cornersCopy[1]*ZOOM_FACTOR, *cornersCopy[2]*ZOOM_FACTOR,cv::Scalar(255,0,255)); cv::line(tag, *cornersCopy[2]*ZOOM_FACTOR, *cornersCopy[3]*ZOOM_FACTOR,cv::Scalar(255,0,255)); cv::line(tag, *cornersCopy[3]*ZOOM_FACTOR, *cornersCopy[0]*ZOOM_FACTOR,cv::Scalar(255,0,255)); cv::line(tag, *cornersCopy[2]*ZOOM_FACTOR, *cornersCopy[0]*ZOOM_FACTOR,cv::Scalar(255,0,255)); cv::line(tag, *cornersCopy[3]*ZOOM_FACTOR, *cornersCopy[1]*ZOOM_FACTOR,cv::Scalar(255,0,255)); cv::line(debugImage, *cornersCopy[0]+origin, *cornersCopy[1]+origin,cv::Scalar(255,0,255)); cv::line(debugImage, *cornersCopy[1]+origin, *cornersCopy[2]+origin,cv::Scalar(255,0,255)); cv::line(debugImage, *cornersCopy[2]+origin, *cornersCopy[3]+origin,cv::Scalar(255,0,255)); cv::line(debugImage, *cornersCopy[3]+origin, *cornersCopy[0]+origin,cv::Scalar(255,0,255)); cv::imshow("ReadBits-full", debugImage); cv::imshow("ReadBits-tag", tag); cv::waitKey(0); #endif return mBits; }