注意,本文只提供学习的思路,严禁违反法律以及破坏信息系统等行为,本文只提供思路
如有侵犯,请联系作者下架
本文滑块识别已同步上线至OCR识别网站: http://yxlocr.nat300.top/ocr/other/21
该验证码会给出某物品所有的角度,根据手指的朝向确定正确的物品,成果图如下:
解决思路
不用于之前的验证码,该验证码在确认物体的同时,还要确认物体角度,由于该物体是一个3D的效果,并且角度360度,也可能去做一个360的分类检测,这样太复杂了,而且很可能没有效果,360分类早在旋转验证码中就提出,是很难拟合数据集的,即使现在拟合了一部分数据集,对没有见过的物体也基本拟合不了,这样就没有做模型的必要了,因为咱们做模型,通常是要泛化出其他数据集,用我的话讲,与其做一个这样的垃圾模型,不如好好研究其他方案
那么,我们参考yolo官方可以看到,yolo-obb模型在检测物体位置的同时还能检测出物体的部分角度,为什么说部分角度呢,因为实际上是检测不出角度的,具体我们来看以下操作
正如yolo-obb官方介绍,这只是基于检测框的旋转框检测而已,并未有任何计算角度可言
其本质上是由正常检测框的两个点扩展到4个点,而且据官网的数据显示,这更多的基于卫星图像,也就是2D图像的旋转框检测,而我们这个作为3D图像的角度检测,那怎么办呢,那玩的就是一个抽象,照样使用,我们使用xanylabeling进行图像的标注,标注如下
我们需要将显示旋转角度打开,然后使用旋转框进行标注
通过快捷键 “zxcv” 旋转所选框,其中:
- z:大角度逆时针旋转
- x:小角度逆时针旋转
- c:小角度顺时针旋转
- v:大角度顺时针旋转
需要注意,旋转后的旋转框可能会超出图片大小,需要矫正过来,但是这样标注就行了吗,当然是不行的,我们标注的标签需要注意,这里必须将四个象限分开,不能用统一的角度进行标注,因为旋转框是计算不了角度,举个例子,我们在标注时,尽管已经确定了0度和180的x1y1x2y2x3y3x4y4的不同(也就是xy上下相反的),在角度上也是0度和180度区别,但是实际在检测中,yolo的推理返回给我们的只有一个0度的框(也就是xy上下相同的),在区分四个象限后,标注标签如下
然后通过一键导出yolo格式后,使用yolo-obb模型进行训练,训练完成后,在使用代码推理后,将每个旋转框的角度计算出来后+对应标签象限的角度即可得到最终的360角度
可以看到,角度不一定完全一样,实际上,通过实战观察也是一样,手指的角度和实际物品的角度并不是完全一样的(部分图中)只需要找到角度最接近的即可,预测代码如下:
model = YOLO("best.pt")
def predict_funxx(img_base64):
img = base642cv(img_base64)
results = model(img)[0]
names = results.names
boxes = results.obb.data.cpu()
confs = boxes[..., 5].tolist()
classes = list(map(int, boxes[..., 6].tolist()))
boxes, angles = xywhr2xyxyxyxy(boxes[..., :5])
hand = None
for i, box in enumerate(boxes):
confidence = round(confs[i], 2)
if confidence < 0.5:
continue
label = classes[i]
points = box.tolist()
x1, y1 = points[0]
angle = angles[i] + (classes[i] * 90)
if y1 > 250:
# 说明是手指
if classes[i] == 0 and angle == 90:
hand = [classes[i], 0]
else:
hand = [classes[i], angle]
# print("hand", classes[i], angle)
break
if hand is None:
print('未检测到手指朝向')
return 1
minangle = 999
minbox = None
for i, box in enumerate(boxes):
confidence = round(confs[i], 2)
if confidence < 0.5:
continue
label = classes[i]
points = box.tolist()
x1, y1 = points[0]
angle = angles[i] + (classes[i] * 90)
if classes[i] == 0 and angle == 90:
angle = 0
if y1 < 250:
# print(classes[i], angle)
if abs(hand[1] - angle) < minangle:
minangle = abs(hand[1] - angle)
minbox = box.tolist()
if not minbox:
print("未检测框位置")
return 1
left1, top1 = [int(b) for b in minbox[0]]
left2, top2 = [int(b) for b in minbox[1]]
center_x = (left1 + left2) // 2
center_y = (top1 + top2) // 2
xx = center_x // 200 + 1
return xx