opencv 截取任意四边形区域的图像
截取任意四边形区域的图像。
mask就是结果。
需要定义四边形区域,分别是 tl, tr, bl, br
std::map<int, std::set<int>> generateBorders(const std::vector<cv::Point> & vecPts) { std::map<int, std::set<int>> borders; cv::Point tl(vecPts[0]), tr(vecPts[1]), bl(vecPts[2]), br(vecPts[3]); // tl to tr double K = double(tl.y-tr.y) / (tl.x - tr.x); for (int i = tl.x; i < tr.x; ++i) borders[i].insert(cvRound(-K*(tl.x - i) + tl.y)); // tr to br if (tr.x != br.x) { K = double(tr.y - br.y) / (tr.x - br.x); for (int i = tr.x; i < br.x; ++i) borders[i].insert(cvRound(-K*(tr.x - i) + tr.y)); } // br to bl K = double(br.y - bl.y) / (br.x - bl.x); for (int i = bl.x; i < br.x; ++i) borders[i].insert(cvRound(-K*(br.x - i) + br.y)); // bl to tl if (bl.x != tl.x) { K = double(bl.y - tl.y) / (bl.x - tl.x); for (int i = tl.x; i < bl.x; ++i) borders[i].insert(cvRound(-K*(bl.x - i) + bl.y)); } for (auto it = borders.begin(); it!=borders.end(); ++it) { if ((*it).second.size() == 2) continue; std::set<int> newone = { *(*it).second.begin(), *(--(*it).second.end())}; (*it).second.swap(newone); } #ifdef DEBUG_CODE cv::Mat disp = cv::imread("1111.PNG", CV_LOAD_IMAGE_COLOR); for (auto it = borders.begin(); it != borders.end(); ++it) { cv::circle(disp, cv::Point((*it).first, *(*it).second.begin()), 1, cv::Scalar(255, 255, 0), -1); cv::circle(disp, cv::Point((*it).first, *(--(*it).second.end())), 1, cv::Scalar(0, 255, 255), -1); } cv::circle(disp, tl, 2, cv::Scalar(0, 0, 255), -1); cv::circle(disp, tr, 2, cv::Scalar(0, 0, 255), -1); cv::circle(disp, bl, 2, cv::Scalar(0, 0, 255), -1); cv::circle(disp, br, 2, cv::Scalar(0, 0, 255), -1); #endif // DEBUG_CODE return borders; } cv::Mat generateMask(const cv::Mat & src, const std::vector<cv::Point> & vecPts) { cv::Mat mask = cv::Mat::zeros(src.size(), CV_8UC1); cv::Point tl(vecPts[0]), tr(vecPts[1]), bl(vecPts[2]), br(vecPts[3]); std::map<int, std::set<int>> borders = generateBorders(vecPts); int minX = std::min(tl.x, bl.x), maxX = std::max(tr.x, br.x), minY = std::min(tl.y, tr.y), maxY = std::max(bl.y, br.y); uchar minZ = std::min(src.at<uchar>(tl), src.at<uchar>(tr)); minZ = std::min(minZ, src.at<uchar>(bl)); minZ = std::min(minZ, src.at<uchar>(br)); for (size_t j= minY; j<maxY; ++j) { const uchar* pS = src.ptr<uchar>(j); uchar* pM = mask.ptr<uchar>(j); for (size_t i = minX; i < maxX; ++i) { // in the region. if (*borders[i].begin() < j && j < *(++borders[i].begin())) { pM[i] = pS[i]; } } } return mask; }