简单剪刀石头布的识别:问题记录

手势识别首先想到两种方法, opencv计算hu, 神经网络图片分类

一. opencv计算hu
1. HU是什么?
一 原理

几何矩是由Hu(Visual pattern recognition by moment invariants)在1962年提出的,具有平移、旋转和尺度不变性。 定义如下:

① (p+q)阶不变矩定义:
在这里插入图片描述
② 对于数字图像,离散化,定义为:
在这里插入图片描述

③ 归一化中心矩定义:

在这里插入图片描述

④Hu矩定义
在这里插入图片描述
要点:
1. pq代表的是维度
2. 矩具有平移不变性(显然)
3. 均一化矩(与零维矩的比值)具有平移,旋转,缩放不变性

所以回到代码实现
首先提取手部信息,两种方法, 一是利用手的颜色提取,二是用手的轮廓提取. 手的颜色在相机中不稳定, 且容易提取到别的东西. 老方法: 二值化+图像形态学操作

        frame = cv.cvtColor(frame, cv.COLOR_RGB2GRAY)
        cv.threshold(frame, 120, 255, cv.THRESH_TOZERO, dst=frame)
        # cv.threshold(frame, 100, 255, cv.THRESH_BINARY, dst=frame)
        kernal = cv.getStructuringElement(cv.MORPH_RECT, (13, 13))
        cv.morphologyEx(frame, cv.MORPH_OPEN, kernal, dst=frame)
findContour,然后利用contour的面积进一步排除,最后调用矩对比函数(先前存好了参考图像)
		contours, hierarchy = cv.findContours(frame, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
        real_contours = []
        contours_hu = []
        for contour in contours:
            contour_area = cv.contourArea(contour)
            if contour_area < 13000 or contour_area > 45000:
                pass
            else:
                real_contours.append(contour)
                # print(contour_area)

        for real_contour in real_contours:
            s = cv.matchShapes(SCISSORS, real_contour, 1, 0.0)
            r = cv.matchShapes(ROCK, real_contour, 1, 0.0)
            p = cv.matchShapes(PAPER, real_contour, 1, 0.0)
            if s < r and s < p:
                print("SCISSORS")
            if r < s and r < p:
                print("ROCK")
            if p < r and p < s:
                print("PAPER")

矩在opencv中还有其他函数,但是原理大同小异.
矩对比, 模板匹配都可以实现图像分类的功能, 矩经过改造后也可以实现模板匹配的全部功能,可以说矩是一种高级的,抽象化,降维的模板匹配.

二. 神经网络
*从这里开始一堆破事开始出现了

  1. 首先想到的是tensorflow官方给出的基础教程
    https://tensorflow.google.cn/tutorials/keras/classification
    其中很简单的,用keras,设计了一个单层的全联通网络,在MNIST上效果很好.所以下意识的(偷懒),打算直接弄过来. 先是利用 glob模块, 和群里发布的数据集开始进行数据清理.
def getPictures():
    paths = glob.glob("E:\\03-project\\02-basketball\\01-handreconization\\pictures\\paper\\*")
    paths1 = glob.glob("E:\\03-project\\02-basketball\\01-handreconization\\pictures\\rock\\*")
    paths2 = glob.glob("E:\\03-project\\02-basketball\\01-handreconization\\pictures\\scissors\\*")
    list_images = []
    for path in paths:
        # print(path)
        src_image = cv.imread(path, -1)
        list_images.append([1, src_image])
    for path in paths1:
        # print(path)
        src_image = cv.imread(path, -1)
        list_images.append([2, src_image])
    for path in paths2:
        # print(path)
        src_image = cv.imread(path, -1)
        list_images.append([3, src_image])
    np.random.shuffle(list_images)
    return list_images

文件的读取很顺利. 但是由于给的训练图像是绿幕图, 所以要进行一个抠图. 也没有怎么百度啥的, 简单的就像根据图像去扣, 效果惨不忍睹,另外一个就是findcontours里面的contour是顺着手内部的,这个问题我在另外一个车道检测的项目中也遇到过,需要设定roi区域, 但是没有找到能根治的方法, 深度学习这一部分问题太多了,还是先等有空了再去学一下把.

	def aaaaaa():
		image = src_image

        image = src_image[:, :, 0] + src_image[:, :, 2]
        cv.threshold(image, 170, 255, cv.THRESH_BINARY, dst=image)

        kernel = cv.getStructuringElement(cv.MORPH_RECT, (57, 57))
        cv.morphologyEx(image, cv.MORPH_DILATE, kernel, image)
        kernel = cv.getStructuringElement(cv.MORPH_RECT, (37, 37))
        cv.morphologyEx(image, cv.MORPH_ERODE, kernel, image)
        low_hand_color = np.array([0, 0, 0])
        high_hand_color = np.array([255, 150, 255])
        mask = cv.inRange(image, low_hand_color, high_hand_color)
        image = cv.bitwise_and(image, image, mask=mask)

        contours, hierarchy = cv.findContours(image, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
        cv.drawContours(src_image, contours, -1, [255, 0, 0], 3)

        cv.imshow("process_frame", image)
        cv.waitKey(0)
    real_contours = []
    contours_hu = []
    for contour in contours:
        contour_area = cv.contourArea(contour)
        if contour_area < 13000 or contour_area > 45000:
            pass
        else:
            real_contours.append(contour)
            # print(contour_area)


    self.contours = real_contours

(未完待续)

全部代码:
Opencv:

import cv2 as cv
import numpy as np

import sys


def Scissors_Rock_Paper():
    scissors_frame = cv.imread("01.jpg")
    scissors_frame = cv.cvtColor(scissors_frame, cv.COLOR_BGR2GRAY)
    cv.threshold(scissors_frame, 100, 255, cv.THRESH_BINARY, dst=scissors_frame)
    kernal = cv.getStructuringElement(cv.MORPH_RECT, (13, 13))
    cv.morphologyEx(scissors_frame, cv.MORPH_OPEN, kernal, dst=scissors_frame)
    scissors_contours, his = cv.findContours(scissors_frame, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
    SCISSORS = np.zeros(scissors_frame.shape)
    cv.drawContours(SCISSORS, scissors_contours, -1, [255], 3)
    # cv.imshow("SCISSORS", SCISSORS)

    rock_frame = cv.imread("02.jpg")
    rock_frame = cv.cvtColor(rock_frame, cv.COLOR_BGR2GRAY)
    cv.threshold(rock_frame, 100, 255, cv.THRESH_BINARY, dst=rock_frame)
    kernal = cv.getStructuringElement(cv.MORPH_RECT, (13, 13))
    cv.morphologyEx(rock_frame, cv.MORPH_OPEN, kernal, dst=rock_frame)
    rock_contours, hir = cv.findContours(rock_frame, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
    ROCK = np.zeros(rock_frame.shape)
    cv.drawContours(ROCK, rock_contours, -1, [255], 3)
    # cv.imshow("ROCK", ROCK)

    paper_frame = cv.imread("03.jpg")
    paper_frame = cv.cvtColor(paper_frame, cv.COLOR_BGR2GRAY)
    cv.threshold(paper_frame, 100, 255, cv.THRESH_BINARY, dst=paper_frame)
    kernal = cv.getStructuringElement(cv.MORPH_RECT, (13, 13))
    cv.morphologyEx(paper_frame, cv.MORPH_OPEN, kernal, dst=paper_frame)
    paper_contours, hi = cv.findContours(paper_frame, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
    PAPER = np.zeros(paper_frame.shape)
    cv.drawContours(PAPER, paper_contours, -1, [255], 3)
    # cv.imshow("PAPER", PAPER)
    return scissors_contours[0], rock_contours[0], paper_contours[0]


SCISSORS, ROCK, PAPER = Scissors_Rock_Paper()


class Frame:
    def __init__(self, path):
        self.cap = cv.VideoCapture(path, cv.CAP_DSHOW)

    def __call__(self, **kwargs):
        self.ret, self.frame = self.cap.read()
        if not self.ret:
            raise Exception
        else:
            return self.frame


class Process:
    def __call__(self, frame, **kwargs):

        self.frame = np.copy(frame)
        cv.GaussianBlur(frame, (3, 3), 0, dst=frame)
        self.frame = frame

        return self.frame

    def draw_self_contours(self, frame):
        cv.drawContours(frame, self.contours, -1, [255, 0, 0], 3)
        return frame

    # 相机曝光是自动的,同时环境曝光也是自动的,无法有效提取肉色,放弃
    def get_hand_by_color(self):
        frame = self.frame
        low_hand_color = np.array([149, 136, 128])
        high_hand_color = np.array([249, 236, 218])
        mask = cv.inRange(frame, low_hand_color, high_hand_color)
        self.frame = cv.bitwise_and(frame, frame, mask=mask)
        return self.frame

    def get_hand_by_findcontours(self):
        frame = self.frame
        frame = cv.cvtColor(frame, cv.COLOR_RGB2GRAY)
        cv.threshold(frame, 120, 255, cv.THRESH_TOZERO, dst=frame)
        # cv.threshold(frame, 100, 255, cv.THRESH_BINARY, dst=frame)
        kernal = cv.getStructuringElement(cv.MORPH_RECT, (13, 13))
        cv.morphologyEx(frame, cv.MORPH_OPEN, kernal, dst=frame)
        contours, hierarchy = cv.findContours(frame, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
        real_contours = []
        contours_hu = []
        for contour in contours:
            contour_area = cv.contourArea(contour)
            if contour_area < 13000 or contour_area > 45000:
                pass
            else:
                real_contours.append(contour)
                # print(contour_area)

        for real_contour in real_contours:
            s = cv.matchShapes(SCISSORS, real_contour, 1, 0.0)
            r = cv.matchShapes(ROCK, real_contour, 1, 0.0)
            p = cv.matchShapes(PAPER, real_contour, 1, 0.0)
            if s < r and s < p:
                print("SCISSORS")
            if r < s and r < p:
                print("ROCK")
            if p < r and p < s:
                print("PAPER")

        self.contours = real_contours
        return frame

    # def decide_hand_meaning(self):


class_frame = Frame(0)
class_process = Process()

while True:
    process_frame = class_frame()
    class_process(process_frame)

    cv.imshow("processing frame", class_process.get_hand_by_findcontours())
    cv.imshow("input_frame", class_process.draw_self_contours(process_frame))

    cv.waitKey(27)

tensorflow:

import tensorflow as tf

import keras

import cv2 as cv

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

import glob


def get_picture(path, kind):
    pictures_paths = glob.iglob(path)
    pictures = []
    for pictures_path in pictures_paths:
        picture = cv.imread(pictures_path)
        pictures.append([kind, picture])
    return pictures


def getPictures():
    paths = glob.glob("E:\\03-project\\02-basketball\\01-handreconization\\pictures\\paper\\*")
    paths1 = glob.glob("E:\\03-project\\02-basketball\\01-handreconization\\pictures\\rock\\*")
    paths2 = glob.glob("E:\\03-project\\02-basketball\\01-handreconization\\pictures\\scissors\\*")
    list_images = []
    for path in paths:
        # print(path)
        src_image = cv.imread(path, -1)
        list_images.append([1, src_image])
    #     image = src_image
    #
    #     image = src_image[:, :, 0] + src_image[:, :, 2]
    #     cv.threshold(image, 170, 255, cv.THRESH_BINARY, dst=image)
    #
    #     kernel = cv.getStructuringElement(cv.MORPH_RECT, (57, 57))
    #     cv.morphologyEx(image, cv.MORPH_DILATE, kernel, image)
    #     kernel = cv.getStructuringElement(cv.MORPH_RECT, (37, 37))
    #     cv.morphologyEx(image, cv.MORPH_ERODE, kernel, image)
    #     low_hand_color = np.array([0, 0, 0])
    #     high_hand_color = np.array([255, 150, 255])
    #     mask = cv.inRange(image, low_hand_color, high_hand_color)
    #     image = cv.bitwise_and(image, image, mask=mask)
    #
    #     contours, hierarchy = cv.findContours(image, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
    #     cv.drawContours(src_image, contours, -1, [255, 0, 0], 3)
    #
    #     cv.imshow("process_frame", image)
    #     cv.waitKey(0)
    # real_contours = []
    # contours_hu = []
    # for contour in contours:
    #     contour_area = cv.contourArea(contour)
    #     if contour_area < 13000 or contour_area > 45000:
    #         pass
    #     else:
    #         real_contours.append(contour)
    #         # print(contour_area)
    #
    # for real_contour in real_contours:
    #     s = cv.matchShapes(SCISSORS, real_contour, 1, 0.0)
    #     r = cv.matchShapes(ROCK, real_contour, 1, 0.0)
    #     p = cv.matchShapes(PAPER, real_contour, 1, 0.0)
    #     if s < r and s < p:
    #         print("SCISSORS")
    #     if r < s and r < p:
    #         print("ROCK")
    #     if p < r and p < s:
    #         print("PAPER")
    #
    # self.contours = real_contours
    for path in paths1:
        # print(path)
        src_image = cv.imread(path, -1)
        list_images.append([2, src_image])
    for path in paths2:
        # print(path)
        src_image = cv.imread(path, -1)
        list_images.append([3, src_image])
    np.random.shuffle(list_images)
    return list_images


TRAIN_DATA = getPictures()
train_images = []
train_index = []
for data in TRAIN_DATA:
    train_images.append(data[1])
    train_index.append(data[0])
    # cv.imshow("data", data[1])
    # print(data[0])
    # cv.waitKey(0)


model = keras.Sequential([
    keras.layers.Flatten(input_shape=(300, 200)),
    keras.layers.Dense(128, activation='relu'),
    keras.layers.Dense(10)
])

model.compile(optimizer='adam',
              loss=keras.losses.SparseCategoricalCrossentropy(from_logits=True),
              metrics=['accuracy'])

model.fit(train_images, train_index, epochs=30)

test_loss, test_acc = model.evaluate(train_images, train_index, verbose=2)
print("TEST accuracy:", test_acc)


SCISSOR_PICTURES = get_picture("", 0)
ROCK_PICTURES = get_picture("", 1)
PAPER_PICTURES = get_picture("", 2)

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值