图片相似判断

上一篇是做的视频镜头分割,虽然分割成功了,但是视频中有一些镜头中,包含一些含有logo的视频帧,这部分视频是我不想要的,所以就需要识别含有logo图像的,然后把这些帧标记出来。
看了很多其他的实现思路,提到了哈希算法,包括有均值哈希算法、差值哈希算法、感知哈希算法。开始的时候,这三种算法都试过,发现都有问题,准确率很低,这时仔细看了每一帧的logo图,才发现logo图的大小不一样,也就是帧之间,logo图可能放大或者缩小了,那么用哈希算法判断的结果就很难去评估这个准确性。因为需要用到阈值,而这个阈值很难设定,所以就放弃了这个方案。
具体哈希实现,大家可以参考以下地址:
哈希算法实现

接下来就是按照其他思路来计算

一、LOGO图片大小不一

由于每一帧的logo图大小不一样,那么在判断之前,必须将logo图片的大小统一,这样才能根据图像数据进行比较判断

二、灰度值

由于图片需要用判断,那么尽量减少颜色的干扰,所以在处理的时候,需要将图片中的颜色去除,所以统一采用灰度值进行处理

三、计算每一行的平均值

图片统一尺寸后,每一行的元素记录了这张图片的特征,那么用每一行的灰度值的均值标识这一行的特征

四、方差

将上一步计算的平均值,求方差,也就是得到了这张图的所有灰度值的方差,然后通过两张图的方差比较,进行相似度的判断。具体方差的判断,我们可以根据多张图的方差曲线图,来做具体的阈值处理。

接下来就是具体的代码实现

1、提取图片数据

#这是一张logo图,用于判断依据的图。由于所使用的logo图色彩差异很大,所以先进行了二值化,方便后期处理
default_img = cv2.imread(default_img_path, cv2.IMREAD_GRAYSCALE)
ret, default_binary = cv2.threshold(default_img, 200, 255, cv2.THRESH_BINARY)

有了上面的原图,下面就是提取一帧图像中的logo图

#这里只包含了部分代码,读取图像,然后找到logo图的位置,从原图中截下对应区域的原图数据
    while success:
        success, frame = cap.read()
        if not success:
            break
        gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)  # 转换成灰度
        shape = np.shape(gray)
        height = shape[0]
        width = shape[1]

        '''
            1、二值化
        '''
        ret, binary = cv2.threshold(gray, 200, 255, cv2.THRESH_BINARY)

        '''
            2、找到需要截取的中间区域的图片
                从中间开始,往前/后找到第一个全部为0的一列,
        '''
        position = find_logo_position(binary, width, height)
        if position is None:
            print("找寻logo位置信息失败 : {0}".format(frame_index))
        else:
            print("找寻logo位置信息成功 : {0}".format(frame_index))
            start_sub_row = position[0]
            end_sub_row = position[1]
            start_sub_col = position[2]
            end_sub_col = position[3]
            # print("{0},{1},{2},{3}".format(start_sub_row, end_sub_row, start_sub_col, end_sub_col))
            frame_sub = frame[start_sub_row:end_sub_row, start_sub_col:end_sub_col]
            is_logo = compare_sub(default_binary, frame_sub)
            print("是否是logo图 : {0} = {1}".format(frame_index, is_logo))

        frame_index += 1

二、计算和比较

def compare_sub(src_binary, sub_frame):
    src_shape = np.shape(src_binary)
    src_h = src_shape[0]
    src_w = src_shape[1]
    sub_shape = np.shape(sub_frame)
    sub_h = sub_shape[0]
    sub_w = sub_shape[1]

    # 由于参考的源已经是最小像素,则新图如果尺寸过小,忽略
    if (src_h - sub_h) > 20 or (src_w - sub_w) > 20:
        return False

    # 以sub的高为固定值,计算sub的理论宽度,比较实际宽度与理论宽度
    theory_sub_width = src_w * sub_h // src_h
    if abs(theory_sub_width - sub_w) > 6:
        return False

    # 对图片进行缩放处理
    crop_size = (src_w, src_h)
    sub_new = cv2.resize(sub_frame, crop_size, interpolation=cv2.INTER_CUBIC)
    sub_gray = cv2.cvtColor(sub_new, cv2.COLOR_BGR2GRAY)  # 转换成灰度
    ret, sub_binary = cv2.threshold(sub_gray, 200, 255, cv2.THRESH_BINARY)  # 二值化

    # 计算每一行的平均值
    src_sum_row = np.sum(src_binary, axis=1)
    src_sum_row = src_sum_row / src_w  # 计算每行的均值
    sub_sum_row = np.sum(sub_binary, axis=1)
    sub_sum_row = sub_sum_row / src_w

    ss_src = get_diff(src_sum_row)
    ss_sub = get_diff(sub_sum_row)

    ss = ss_sub - ss_src
    ss = np.fabs(ss)


    n = 0
    for value in ss:
        if value <= 1.0:
            n += 1

    if (n / len(ss)) > 0.9:
        x = range(src_h)
        plt.figure("avg")
        plt.plot(x, ss_src, marker="*", label="$walk01$")
        plt.plot(x, ss_sub, marker="*", label="$walk03$")
        plt.title("compare")
        plt.legend()
        plt.show()
        return True
    else:
        return False

3、计算方差

def get_diff(source):
    size = len(source)
    ave_src = sum(source) / size  # 总的平均值
    s_src = source - ave_src  # 计算每个值与平均值的差值
    ss_src = s_src * s_src / size  # 方差
    return ss_src

说明
在上面比较的代码中,我对logo图的方差与原图logo方差的差值进行了取绝对值,这是因为我需要看两张图在同一个位置特征上的波动情况。然后根据波动情况的范围,来判断这个位置是否相近,当走势中准确度达到90%时,我就认为这张图是原图。
这个比较和判断结果,我是通过多张图的logo解析结果,方差变化情况决定的。以下是对应的参考情况。

7820436-824bdc95e132cbcf.png
比较图1

7820436-9ecb6d848fd8d4ab.png
比较图2

通过上面两个图,我们就能大概的选择自己需要判断的范围了。

以上内容是我自己根据一些文章,然后结合自己的需求,改进的方案,有问题或者需要探讨的,欢迎留言讨论

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值