From 9af9e465ac046b6f39968871995eff7535d8e983 Mon Sep 17 00:00:00 2001 From: Sallee1 <885331635@qq.com> Date: Sat, 3 Jun 2023 14:52:46 +0800 Subject: [PATCH] =?UTF-8?q?feat:=E9=87=8D=E5=86=99=E8=A7=86=E8=A7=92?= =?UTF-8?q?=E8=AF=86=E5=88=AB=E7=AE=97=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/algorithms/algorithms.rotation.h | 195 +++++++++++------- cvAutoTrack/src/version/version_tag.tag | 2 +- 2 files changed, 118 insertions(+), 79 deletions(-) diff --git a/cvAutoTrack/src/algorithms/algorithms.rotation.h b/cvAutoTrack/src/algorithms/algorithms.rotation.h index 0b704e79..8c1c026a 100644 --- a/cvAutoTrack/src/algorithms/algorithms.rotation.h +++ b/cvAutoTrack/src/algorithms/algorithms.rotation.h @@ -11,96 +11,135 @@ struct rotation_calculation_config double lastRotate = 0; +void rotation_calculation(cv::Mat& giMiniMapRef, double& a, rotation_calculation_config& config); //算法1,基于Alpha通道,高精度 +void rotation_calculation_2nd(cv::Mat& giMiniMapRef, double& a, rotation_calculation_config& config); //算法2,基于屏幕空间,低精度 + void rotation_calculation(cv::Mat& giMiniMapRef, double&a, rotation_calculation_config& config) { - cv::Mat img_object(giMiniMapRef(cv::Rect(40, 40, giMiniMapRef.cols - 80, giMiniMapRef.rows - 80))); + if (giMiniMapRef.channels() != 4) + return rotation_calculation_2nd(giMiniMapRef, a, config); + //取Alpha通道 + std::vectorscr_channels; + split(giMiniMapRef, scr_channels); + cv::Mat alpha = scr_channels[3]; + + double minVal; + cv::minMaxIdx(alpha, &minVal, NULL, NULL, NULL); + if(minVal == 255) //没有透明通道 + return rotation_calculation_2nd(giMiniMapRef, a, config); + + cv::Point2i center(giMiniMapRef.size[1] / 2, giMiniMapRef.size[0] / 2); + cv::Size2i miniMap_size = giMiniMapRef.size(); + //极坐标 + cv::warpPolar(alpha.clone(), alpha, cv::Size2i(512, 512), center, 360, cv::WARP_POLAR_LINEAR | cv::INTER_LINEAR); + alpha = alpha(cv::Rect2d( + miniMap_size.width * 0.1, 0, + miniMap_size.width * 0.3, alpha.size[0])); + cv::rotate(alpha.clone(), alpha, cv::ROTATE_90_COUNTERCLOCKWISE); + //滤波 + cv::Scharr(alpha.clone(), alpha, CV_32FC1, 1, 0); + + //列求和&平滑 + cv::Mat sumOfImg; + cv::reduce(alpha, sumOfImg, 0, cv::REDUCE_SUM, CV_32F); + sumOfImg = cv::repeat(sumOfImg, 1, 2); + cv::blur(sumOfImg.clone(), sumOfImg, cv::Size2i(5, 1), cv::Point2i(-1, -1), cv::BORDER_REPLICATE); + sumOfImg = sumOfImg(cv::Rect2i(256, 0, 512, 1)); + + //求角度 + float angles[2]; + cv::Point2i maxLoc,minLoc; + cv::minMaxLoc(sumOfImg, NULL, NULL, &minLoc, &maxLoc); + angles[0] = std::fmod((minLoc.x / 512.0) * 360, 360); + angles[1] = std::fmod((maxLoc.x / 512.0) * 360, 360); + + if (angles[1] < angles[0]) + angles[1] += 360; + + + + if ((std::abs(angles[1] - angles[0] - 90) > 15)) + return rotation_calculation_2nd(giMiniMapRef, a, config); + + a = -((angles[0] + angles[1]) / 2) + 90; + if (a < -180) a += 360; + lastRotate = a; +} - if (img_object.channels() != 4) +cv::Mat cvMatRoll(const cv::Mat& src,cv::Point2d shift) +{ + cv::Mat transFormMat = cv::Mat::zeros(2, 3, CV_32FC1); + cv::Mat dst; + transFormMat.at(0, 0) = 1; + transFormMat.at(1, 1) = 1; + transFormMat.at(0, 2) = shift.x; + transFormMat.at(1, 2) = shift.y; + cv::warpAffine(src, dst, transFormMat, src.size(), cv::INTER_NEAREST, cv::BORDER_WRAP); + return dst; +} + +void rotation_calculation_2nd(cv::Mat& giMiniMapRef, double& a, rotation_calculation_config& config) +{ + cv::Point2i center(giMiniMapRef.size[1] / 2, giMiniMapRef.size[0] / 2); + cv::Size2i miniMap_size = giMiniMapRef.size(); + + //极坐标 + cv::Mat img_object; + cv::warpPolar(giMiniMapRef, img_object, cv::Size2i(512, 512), center, 360, cv::WARP_POLAR_LINEAR | cv::INTER_LINEAR); + + img_object = img_object(cv::Rect2d( + miniMap_size.width * 0.1, 0, + miniMap_size.width * 0.3, img_object.size[0])); + cv::rotate(img_object.clone(), img_object, cv::ROTATE_90_COUNTERCLOCKWISE); + + //边缘提取 + img_object.convertTo(img_object, CV_32F); + img_object /= 255; + float alpha = 0.25; + + cv::Mat img_edge_arr[2] = { + cv::abs(img_object * (1 - alpha) + alpha - cvMatRoll(img_object,cv::Point2d(-5,0))), + cv::abs(img_object * (1 - alpha) + alpha - cvMatRoll(img_object,cv::Point2d(5,0))) + }; + + float angles[2]; + for (int i = 0; i < 2; i++) { - config.error = true; - config.err = { 3003,"获取视角朝向时,原神小地图区域没有取到透明通道" }; - return; + //提取边缘信息 + cv::pow(img_edge_arr[i].clone(), 2, img_edge_arr[i]); + img_edge_arr[i] = (img_edge_arr[i] < 0.001); + std::vector bgr_planes; + cv::split(img_edge_arr[i], bgr_planes); + img_edge_arr[i] = bgr_planes[0] & bgr_planes[1] & bgr_planes[2]; + + //形态学滤波 + cv::Mat kernel = cv::getStructuringElement(cv::MORPH_RECT, cv::Point(1, 3)); + cv::morphologyEx(img_edge_arr[i].clone(), img_edge_arr[i], cv::MORPH_OPEN, kernel); + //列求和&平滑 + cv::Mat sumOfImg; + cv::reduce(img_edge_arr[i], sumOfImg, 0, cv::REDUCE_SUM,CV_32F); + sumOfImg = cv::repeat(sumOfImg, 1, 2); + cv::blur(sumOfImg.clone(), sumOfImg, cv::Size2i(5, 1), cv::Point2i(-1, -1), cv::BORDER_REPLICATE); + sumOfImg = sumOfImg(cv::Rect2i(256, 0, 512, 1)); + //求峰值 + cv::Point2i maxLoc; + cv::minMaxLoc(sumOfImg, NULL, NULL, NULL, &maxLoc); + angles[i] = std::fmod((maxLoc.x / 512.0) * 360, 360); } - //if (capture->mode == Capture::DirectX) - //{ - // config.error = true; - // config.err = { 3004,"DX模式下,原神小地图区域无法取到透明通道" }; - // return; - //} - - std::vectorscr_channels; - - split(img_object, scr_channels); - - cv::Mat Alpha = scr_channels[3]; - - Alpha = 255.0 - Alpha; - - Alpha = Alpha * 2; - - cv::threshold(Alpha, Alpha, 150, 0, cv::THRESH_TOZERO_INV); - cv::threshold(Alpha, Alpha, 50, 0, cv::THRESH_TOZERO); - cv::threshold(Alpha, Alpha, 50, 255, cv::THRESH_BINARY); + if (angles[1] < angles[0]) + angles[1] += 360; - cv::Point center = cv::Point(Alpha.cols / 2, Alpha.rows / 2); - double min_radius = center.x < center.y ? center.x : center.y; - - cv::circle(Alpha, center, static_cast(min_radius * 1.21), cv::Scalar(0, 0, 0), static_cast(min_radius * 0.42)); - cv::circle(Alpha, center, static_cast(min_radius * 0.3), cv::Scalar(0, 0, 0), -1); - - cv::Mat dilate_element = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(4, 4)); - cv::dilate(Alpha, Alpha, dilate_element); - cv::Mat erode_element = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(4, 4)); - cv::erode(Alpha, Alpha, erode_element); - - erode_element = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(4, 4)); - cv::erode(Alpha, Alpha, erode_element); - dilate_element = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(4, 4)); - cv::dilate(Alpha, Alpha, dilate_element); - - //传入黑白图 - //根据白块部分计算视角中心坐标 - std::vector> contours; - std::vector hierarcy; - - cv::findContours(Alpha, contours, hierarcy, 0, 1); - - std::vector boundRect(contours.size()); //定义外接矩形集合 - - if (contours.size() == 0) + if ((std::abs(angles[1] - angles[0] - 90) > 20)) { config.error = true; - config.err = { 3005 ,"获取视角朝向时,没有提取出视角扇形区域" }; + config.err = { 3006,"获取视角的误差过大" }; a = lastRotate; return; } - cv::Point p; - int maxBlack = 0; - int maxId = 0; - - for (int i = 0; i < contours.size(); i++) - { - if (contours[i].size() > maxBlack) - { - maxBlack = static_cast(contours[i].size()); - maxId = i; - } - boundRect[i] = cv::boundingRect(cv::Mat(contours[i])); - - } - - p = cv::Point(boundRect[maxId].x + boundRect[maxId].width / 2, boundRect[maxId].y + boundRect[maxId].height / 2); - - // double res; -#ifdef _DEBUG - circle(Alpha, p, 3, cv::Scalar(255, 0, 0)); - line(Alpha, p, cv::Point(img_object.cols / 2, img_object.rows / 2), cv::Scalar(0, 255, 0)); - cv::imshow("Img", Alpha); -#endif - p = p - cv::Point(img_object.cols / 2, img_object.rows / 2); - - a = TianLi::Utils::Line2Angle(p); + a = -((angles[0] + angles[1]) / 2) + 90; + if (a < -180) a += 360; lastRotate = a; + return; } \ No newline at end of file diff --git a/cvAutoTrack/src/version/version_tag.tag b/cvAutoTrack/src/version/version_tag.tag index 306f8f18..449165fd 100644 --- a/cvAutoTrack/src/version/version_tag.tag +++ b/cvAutoTrack/src/version/version_tag.tag @@ -1 +1 @@ -7.8.104 +7.8.161