基本思想:opencv仿射變換不是太準,存在于嵌套仿射的情況,存在這樣的問題,在角點的四個外圍坐标仿射為正向坐标之後,通過仿射矩陣M去計算内部存在的嵌套矩形框,計算存在偏差,同時以截圖為遮擋,仿射的外圍四個角點還是存在誤差的,需要添加平移參數調整
情況一:
測試圖檔
測試代碼
#include<iostream>
#include<opencv2/opencv.hpp>
using namespace std;
using namespace cv;
double EuDis(Point pt1, Point pt2) {
return sqrt((pt2.x - pt1.x) * (pt2.x - pt1.x) + (pt2.y - pt1.y) * (pt2.y - pt1.y));
}
int main() {
Mat src = imread("../demo.jpg");
Mat src_clone=src.clone();
vector<vector<Point>> contours;
std::vector<Point> item;
item.emplace_back(cv::Point(363, 62));
item.emplace_back(cv::Point(765, 199));
item.emplace_back(cv::Point(505, 659));
item.emplace_back(cv::Point(62, 507));
contours.emplace_back(item);
item.clear();
item.emplace_back(cv::Point(378, 290));
item.emplace_back(cv::Point(456, 252));
item.emplace_back(cv::Point(491, 295));
item.emplace_back(cv::Point(417, 332));
contours.emplace_back(item);
item.clear();
for(int i=0;i<contours.size();i++){
for(int j=0;j<contours[i].size();j++){
circle(src, cv::Point(contours[i][j].x, contours[i][j].y), 10, Scalar(255, 0, 0), -1);
if(j!=contours[i].size()-1){
line(src, cv::Point(contours[i][j].x, contours[i][j].y), cv::Point(contours[i][j+1].x, contours[i][j+1].y), Scalar(255, 0, 0),2, LINE_8);
}else {
line(src, cv::Point(contours[i][j].x, contours[i][j].y), cv::Point(contours[i][0].x, contours[i][0].y), Scalar(255, 0, 0),2, LINE_8);
}
}
}
vector<Point> srcPts;
double new_area = 0;
for (int i = 0; i < contours.size(); i++) {
double area = contourArea(contours[i]);
if (area > new_area) {
srcPts = {contours[i][0], contours[i][1], contours[i][2], contours[i][3]};
new_area = area;
}
}
double LeftHeight = EuDis(srcPts[0], srcPts[3]);
double RightHeight = EuDis(srcPts[1], srcPts[2]);
double MaxHeight = max(LeftHeight, RightHeight);
double UpWidth = EuDis(srcPts[0], srcPts[1]);
double DownWidth = EuDis(srcPts[2], srcPts[3]);
double MaxWidth = max(UpWidth, DownWidth);
Point2f SrcAffinePts[4] = {Point2f(srcPts[0]), Point2f(srcPts[1]), Point2f(srcPts[2]), Point2f(srcPts[3])};
Point2f DstAffinePts[4] = {Point2f(0, 0), Point2f(MaxWidth, 0), Point2f(MaxWidth, MaxHeight),
Point2f(0, MaxHeight)};
Mat M = getPerspectiveTransform(SrcAffinePts, DstAffinePts);
Mat DstImg;
warpPerspective(src_clone, DstImg, M, Point(MaxWidth,MaxHeight));
std::cout << M << std::endl;
float a00 = M.at<cv::Vec3d>(0, 0)[0];
float a01 = M.at<cv::Vec3d>(0, 0)[1];
float a02 = M.at<cv::Vec3d>(0, 0)[2];
float a10 = M.at<cv::Vec3d>(1, 0)[0];
float a11 = M.at<cv::Vec3d>(1, 0)[1];
float a12 = M.at<cv::Vec3d>(1, 0)[2];
float a20 = M.at<cv::Vec3d>(2, 0)[0];
float a21 = M.at<cv::Vec3d>(2, 0)[1];
float a22 = M.at<cv::Vec3d>(2, 0)[2];
//cosx siny tx a00 a01 a02
//-sinx cosy ty a10 a11 a12
//0 0 1 a20 a21 a22
//矯正畸變不準 需要調整包含物體的坐标
int cof=5;
std::vector<std::vector<cv::Point>> new_contours;
for (int i = 0; i < contours.size(); i++) {
std::vector<cv::Point> item;
double new_x=0;
double new_y=0;
for (int j = 0; j < contours[i].size(); j++) {
if(i==0){
new_x=DstAffinePts[j].x;
new_y=DstAffinePts[j].y;
}else {
new_x = contours[i][j].x * a00+ contours[i][j].y * a01 + a02-cof;
new_y = contours[i][j].x * a10 + contours[i][j].y * a11 + a12-4;
}
item.emplace_back(cv::Point(new_x, new_y));
}
new_contours.emplace_back(item);
}
for(int i=0;i<new_contours.size();i++){
for(int j=0;j<new_contours[i].size();j++){
circle(DstImg, cv::Point(new_contours[i][j].x, new_contours[i][j].y), 10, Scalar(0, 0, 255), -1);
if(j!=new_contours[i].size()-1){
line(DstImg, cv::Point(new_contours[i][j].x, new_contours[i][j].y), cv::Point(new_contours[i][j+1].x, new_contours[i][j+1].y), Scalar(0, 0, 255),2, LINE_8);
}else {
line(DstImg, cv::Point(new_contours[i][j].x, new_contours[i][j].y), cv::Point(new_contours[i][0].x, new_contours[i][0].y), Scalar(0, 0, 255),2, LINE_8);
}
}
}
imshow("Dst", DstImg);
imshow("src", src);
waitKey(0);
destroyAllWindows();
return 0;
}
測試結果
情況二:測試圖檔
測試代碼
#include<iostream>
#include<opencv2/opencv.hpp>
using namespace std;
using namespace cv;
double EuDis(Point pt1, Point pt2) {
return sqrt((pt2.x - pt1.x) * (pt2.x - pt1.x) + (pt2.y - pt1.y) * (pt2.y - pt1.y));
}
int main() {
Mat src = imread("../Selection_017.png");
Mat src_clone=src.clone();
vector<vector<Point>> contours;
std::vector<Point> item;
item.emplace_back(cv::Point(87, 143));
item.emplace_back(cv::Point(548, 147));
item.emplace_back(cv::Point(601, 364));
item.emplace_back(cv::Point(54, 362));
contours.emplace_back(item);
item.clear();
item.emplace_back(cv::Point(252, 247));
item.emplace_back(cv::Point(398, 246));
item.emplace_back(cv::Point(402, 269));
item.emplace_back(cv::Point(249, 269));
contours.emplace_back(item);
item.clear();
item.emplace_back(cv::Point(441, 208));
item.emplace_back(cv::Point(441, 233));
item.emplace_back(cv::Point(478, 232));
item.emplace_back(cv::Point(474, 208));
contours.emplace_back(item);
item.clear();
item.emplace_back(cv::Point(155, 223));
item.emplace_back(cv::Point(155, 246));
item.emplace_back(cv::Point(192, 245));
item.emplace_back(cv::Point(193, 222));
contours.emplace_back(item);
item.clear();
for(int i=0;i<contours.size();i++){
for(int j=0;j<contours[i].size();j++){
circle(src, cv::Point(contours[i][j].x, contours[i][j].y), 10, Scalar(255, 0, 0), -1);
if(j!=contours[i].size()-1){
line(src, cv::Point(contours[i][j].x, contours[i][j].y), cv::Point(contours[i][j+1].x, contours[i][j+1].y), Scalar(255, 0, 0),2, LINE_8);
}else {
line(src, cv::Point(contours[i][j].x, contours[i][j].y), cv::Point(contours[i][0].x, contours[i][0].y), Scalar(255, 0, 0),2, LINE_8);
}
}
}
vector<Point> srcPts;
double new_area = 0;
for (int i = 0; i < contours.size(); i++) {
double area = contourArea(contours[i]);
if (area > new_area) {
srcPts = {contours[i][0], contours[i][1], contours[i][2], contours[i][3]};
new_area = area;
}
}
double LeftHeight = EuDis(srcPts[0], srcPts[3]);
double RightHeight = EuDis(srcPts[1], srcPts[2]);
double MaxHeight = max(LeftHeight, RightHeight);
double UpWidth = EuDis(srcPts[0], srcPts[1]);
double DownWidth = EuDis(srcPts[2], srcPts[3]);
double MaxWidth = max(UpWidth, DownWidth);
Point2f SrcAffinePts[4] = {Point2f(srcPts[0]), Point2f(srcPts[1]), Point2f(srcPts[2]), Point2f(srcPts[3])};
Point2f DstAffinePts[4] = {Point2f(0, 0), Point2f(MaxWidth, 0), Point2f(MaxWidth, MaxHeight),
Point2f(0, MaxHeight)};
Mat M = getPerspectiveTransform(SrcAffinePts, DstAffinePts);
Mat DstImg;
warpPerspective(src_clone, DstImg, M, Point(MaxWidth,MaxHeight));
std::cout << M << std::endl;
float a00 = M.at<cv::Vec3d>(0, 0)[0];
float a01 = M.at<cv::Vec3d>(0, 0)[1];
float a02 = M.at<cv::Vec3d>(0, 0)[2];
float a10 = M.at<cv::Vec3d>(1, 0)[0];
float a11 = M.at<cv::Vec3d>(1, 0)[1];
float a12 = M.at<cv::Vec3d>(1, 0)[2];
float a20 = M.at<cv::Vec3d>(2, 0)[0];
float a21 = M.at<cv::Vec3d>(2, 0)[1];
float a22 = M.at<cv::Vec3d>(2, 0)[2];
//cosx siny tx a00 a01 a02
//-sinx cosy ty a10 a11 a12
//0 0 1 a20 a21 a22
//矯正畸變不準 需要調整包含物體的坐标
int cof=25;
std::vector<std::vector<cv::Point>> new_contours;
for (int i = 0; i < contours.size(); i++) {
std::vector<cv::Point> item;
double new_x=0;
double new_y=0;
for (int j = 0; j < contours[i].size(); j++) {
if(i==0){
new_x=DstAffinePts[j].x;
new_y=DstAffinePts[j].y;
}else {
new_x = contours[i][j].x * a00+ contours[i][j].y * a01 + a02-cof;
new_y = contours[i][j].x * a10 + contours[i][j].y * a11 + a12-cof;
}
item.emplace_back(cv::Point(new_x, new_y));
}
new_contours.emplace_back(item);
}
for(int i=0;i<new_contours.size();i++){
for(int j=0;j<new_contours[i].size();j++){
circle(DstImg, cv::Point(new_contours[i][j].x, new_contours[i][j].y), 10, Scalar(0, 0, 255), -1);
if(j!=new_contours[i].size()-1){
line(DstImg, cv::Point(new_contours[i][j].x, new_contours[i][j].y), cv::Point(new_contours[i][j+1].x, new_contours[i][j+1].y), Scalar(0, 0, 255),2, LINE_8);
}else {
line(DstImg, cv::Point(new_contours[i][j].x, new_contours[i][j].y), cv::Point(new_contours[i][0].x, new_contours[i][0].y), Scalar(0, 0, 255),2, LINE_8);
}
}
}
cv::imwrite("dst.jpg",DstImg);
imshow("Dst", DstImg);
cv::imwrite("src.jpg",src);
imshow("src", src);
waitKey(0);
destroyAllWindows();
return 0;
}
測試結果
原圖