如果想让跳一跳自动跳的话,那么最重要的就是要通过图像的分析,找到下一个台子的中心点以及当前时刻小人的脚的坐标,楼主自己想了一个算法,也算能够勉强识别这两个关键点了,但是不是图像识别的算法,所以容易收到图像噪声的干扰,稳定性不大高。。但是总算是能够实现自动跳的。。
下面分别讲一下识别这两个点的思路以及相应的代码。
(1)识别下一个台子的中心:先把图像转换成灰度图,然后得到差分图像,背景这种颜色均一的部分通常在差分图像中亮度值直接为0了,所以只需要自上而下进行光栅扫描,碰到第一个非零点,定义为台子的最高点(这个针对方形和圆形的台子都适用),将台子最高点的横坐标作为中心点的横坐标,然后这个最高点继续往下,找到台子的最宽水平面(通过颜色判断),定义为中心点的纵坐标。
代码:
//分析图像集,从时域和空域一起得到下一个块的中心点
func getMidPoint(imageSet: [UIImage]) -> (Int, Int) {
var point = (0, 0)
let width = Int(imageSet[0].size.width)
let height = Int(imageSet[1].size.height)
let mImageOne = self.getGrayImage(sourceImage: imageSet[0])
let mImageTwo = self.getGrayImage(sourceImage: imageSet[1])
//将image2转换为二维矩阵,下面data2为这二维矩阵的指针
let CGImageTwo = mImageTwo.cgImage
let pPixelDataTwo = CGImageTwo?.dataProvider?.data
let pData2: UnsafePointer<UInt8> = CFDataGetBytePtr(pPixelDataTwo)
//将image1转换为二维矩阵,下面data1为这二维矩阵的指针
let CGImageOne = mImageOne.cgImage
let pPixelDataOne = CGImageOne?.dataProvider?.data
let pData1: UnsafePointer<UInt8> = CFDataGetBytePtr(pPixelDataOne)
//得到差值图像
let num = width*height
var diffImageArray: [Int16] = []
var diffRect = [[Int16]]()
for y in 0..<height {
var tmp: [Int16] = []
for x in 1..<width {
let pos = y * width + x
let pix = Int16(pData2[pos]) - Int16(pData2[pos-1])
tmp.append(pix)
}
tmp.append(0)
diffRect.append(tmp)
}//2D
//find the toppest point of the new block
let initial_height = 400 //上方是分数等控件,不需要搜索
let searchwindow_height = 200
var findTopPoint: Bool = false
var topPointX: Int = 0
var topPointY: Int = 0
let sigma = 0 //允许误差
let (er,eg,eb) = self.getPixelColor(pos: CGPoint.init(x: 0, y: initial_height), image: imageSet[1]) //background color
var diff: [Double] = []
var count_all: [Int] = []
for y in initial_height...(initial_height+searchwindow_height) {
var count = 0
var difftmp: Int32 = 0
for x in 0..<width {
if diffRect[y][x] > sigma {
count = count + 1
let (r,g,b) = self.getPixelColor(pos: CGPoint.init(x: x, y: y), image: imageSet[1])
difftmp = (abs(Int32(r)-Int32(er)) + abs(Int32(g)-Int32(eg)) + abs(Int32(b)-Int32(eb)))
if difftmp > 10 {
findTopPoint = true
topPointX = x
topPointY = y
break
}
}
}
if findTopPoint {
break
}
}
//find the mid point
var best_obj_width = 0
var bestY = 0
var bestX = 0
let searchMid_height = 100
for y in (topPointY+1)...(topPointY+searchMid_height) {
let range = min(topPointX-1, width-topPointX-1)
var obj_width = 0
if diffRect[y][topPointX] <= sigma && diffRect[y][topPointX] >= 0 {
for i in 0...range {
if diffRect[y][topPointX+i] <= sigma && diffRect[y][topPointX+i] >= 0 && diffRect[y][topPointX-i] >= 0 && diffRect[y][topPointX-i] <= sigma {
obj_width = obj_width + 1
} else {
break
}
}
if obj_width > best_obj_width && obj_width != range {
best_obj_width = obj_width
bestY = y
bestX = topPointX
}
}
else {
continue
}
}
point = (bestX, bestY)
print("point:\(point)")
return point
}
(2)找到小人脚的坐标
扫描相应的游戏区域,通过亮度值识别小人的坐标
代码:
func getGuyPoint(image: [[UInt8]], width: CGFloat, height: CGFloat, midX: Int, midY: Int) -> (Int, Int) {
let bandwidth = Int(width) - 40 - midX
let search_height = 300
var bestMAD: Int32 = 1073741823
var bestPosX = 0
var bestPosY = 0
var isFound : Bool = false
for y in (midY-100)...(midY+search_height) {
var left = midX > Int(width / 2) ? 0 : midX
var right = midX > Int(width / 2) ? midX : Int(width) - 40
let tmp = image[midX][midY]
for x in left..<right {
if image[y][x] <= 65 && image[y][x] < tmp && image[y + 112][x] <= 65 && image[y + 112][x] <= tmp{
bestPosY = y
bestPosX = x
isFound = true
break
}
}
if isFound {
break
}
}
return (bestPosX, bestPosY + 125)
}