情景
这两天在玩重装战姬,因此分享一下遇到的问题和解法:敌方要攻打某个据点,并以虚线表示目标点,需要拖动我方部队到目标点防守。
场景如下图:
example.png
解决思路
- 截图(废话)
- 识别出我方位置
- 筛选出红色
- 获取线条
- 通过方程计算出直线的交点
- 将我方部分拖拽到交点
下面给出3-5的详细代码和说明
importClass(org.opencv.core.MatOfByte)
importClass(org.opencv.imgcodecs.Imgcodecs)
importClass(org.opencv.imgproc.Imgproc)
importClass(org.opencv.core.Core)
importClass(org.opencv.core.CvType)
importClass(org.opencv.core.Mat)
importClass(org.opencv.core.MatOfPoint)
importClass(org.opencv.core.MatOfPoint2f)
importClass(org.opencv.core.Point)
importClass(org.opencv.core.Size)
importClass(org.opencv.core.Scalar)
importClass(java.io.ByteArrayInputStream)
importClass(java.util.ArrayList)
function getCrossPoint (img) {
var hsv = new Mat()
var redImg = new Mat()
// 将原图片转换成hsv格式
Imgproc.cvtColor(img.mat, hsv, Imgproc.COLOR_BGR2HSV)
// 筛选颜色,将结果保存到redImg,第一个Scalar是hsv颜色下限,第二个为hsv上限。这里筛选的是红色,这部分红色在hsv分量里位于紫色区间,因此取紫色分量范围。
Core.inRange(hsv, new Scalar(120, 43, 46), new Scalar(150, 255, 255), redImg)
var lines = new Mat()
// 获取直线数组,由于这里是虚线,因此最后一个参数(间距)设长一点,为30
Imgproc.HoughLinesP(redImg, lines, 1, Math.PI/180, 80, 80, 30)
if (!lines) {
return null
}
// 获取前两条直线(也可以遍历所有的直线,不过这里默认只有一个交点,所以取前两条就够用)
var lineA = lines.get(0, 0)
var lineB = lines.get(1, 0)
log('lineA', lineA)
log('lineB', lineB)
if (!lineA || !lineB) {
return null
}
return checkPoint(lineA, lineB)
}
// 通过方程计算交点
function checkPoint(LineA, LineB)
{
if (!LineA || !LineB) {
return null
}
//求出LineA斜率
var ka = (LineA[3] - LineA[1]) / (LineA[2] - LineA[0])
//求出LineB斜率
var kb = (LineB[3] - LineB[1]) / (LineB[2] - LineB[0])
// 可以对斜率进行筛选,比如斜率相等、差值小于5%则返回null
// 如果斜率差值小于5%,则返回null
if (Math.abs((ka - kb)/ka) < 0.05) {
return null
}
var x = parseInt((ka*LineA[0] - LineA[1] - kb*LineB[0] + LineB[1]) / (ka - kb));
var y = parseInt((ka*kb*(LineA[0] - LineB[0]) + ka*LineB[1] - kb*LineA[1]) / (ka - kb));
// 对交点进行筛选,如果交点不在两条线段上,则返回null
var x = parseInt((ka*LineA[0] - LineA[1] - kb*LineB[0] + LineB[1]) / (ka - kb));
var y = parseInt((ka*kb*(LineA[0] - LineB[0]) + ka*LineB[1] - kb*LineA[1]) / (ka - kb));
if (
(x - LineA[0]) * (x - LineA[2]) <= 0 && (y - LineA[1]) * (y - LineA[3]) <= 0 &&
(x - LineB[0]) * (x - LineB[2]) <= 0 && (y - LineB[1]) * (y - LineB[3]) <= 0
) {
return [x, y]
} else {
return null
}
}
export default {
getCrossPoint
}
(有些包没有用到,偷懒直接用上次例子的包了)
值得注意的是,importClass加载的opencv包需要在调用了auto.pro的images.xxx函数之后才能生效。因此在执行getCrossPoint之前,应该先随便执行一个images的read以外的函数。
网友评论