Python中因为软拷贝导致调用face_recognition.encodings(img)出现的典型问题

news2024/11/15 13:49:28

问题描述

在使用face_recognition时,在对np.array格式图片使用形如`new_img = img[x:y, a:b]``进行裁剪后,因为是软拷贝,导致前后图片其实引用了同一个face_locations, 从而导致莫名其妙的错误。

问题代码

检测一张照片里的人脸,并进行encode:

image = face_recognition.load_image_file("Keanu Reeves.jpg")
face_locations = face_recognition.face_locations(image)

top, right, bottom, left= face_locations[0]

face_image = image[top:bottom, left:right] # 不知道什么原因,改变尺寸后导致无法编码
face_encoding = face_recognition.face_encodings(face_image)

运行结果:

compute_face_descriptor(): incompatible function arguments. The following argument types are supported:
    1. (self: _dlib_pybind11.face_recognition_model_v1, img: numpy.ndarray[(rows,cols,3),numpy.uint8], face: _dlib_pybind11.full_object_detection, num_jitters: int = 0, padding: float = 0.25) -> _dlib_pybind11.vector
    2. (self: _dlib_pybind11.face_recognition_model_v1, img: numpy.ndarray[(rows,cols,3),numpy.uint8], num_jitters: int = 0) -> _dlib_pybind11.vector
    3. (self: _dlib_pybind11.face_recognition_model_v1, img: numpy.ndarray[(rows,cols,3),numpy.uint8], faces: _dlib_pybind11.full_object_detections, num_jitters: int = 0, padding: float = 0.25) -> _dlib_pybind11.vectors

...

在上面的例子中,直接将改变尺寸后的图片face_image 进行编码,是无法编码的。
但是如果将其保存成图片,然后再打开,就可以编码了

image = face_recognition.load_image_file("Keanu Reeves.jpg")
face_locations = face_recognition.face_locations(image)

top, right, bottom, left= face_locations[0]

face_image = image[top:bottom, left:right] 

old_image = face_image[:]  # 不保存为图片,只是保存在内存里

cv2.imwrite("new.jpg", face_image) # 保存为图片

face_image = face_recognition.load_image_file("new.jpg") # 打开保存的图片,进行编码就可以

face_encoding = face_recognition.face_encodings(face_image)
plt.imshow(face_image)

在这里插入图片描述

按照上面的方式又能够成功。难道保存在内存里的值和重新打开图片的值,不一样吗?

face_image == old_image

运行结果:

array([[[False,  True, False],
        [False, False, False],
        [False, False, False],
        ...,
        [False, False, False],
        [False, False, False],
        [False, False, False]],

       [[False,  True, False],
        [False,  True, False],
        [False,  True, False],
        ...,
        [False, False, False],
        [False, False, False],
        [False, False, False]],

       [[False,  True, False],
        [False, False, False],
        [False,  True, False],
        ...,

可以看出,两者的数据确实是不一样的。这是为什么呢?

还有一个更奇葩的

如果这里只是将top, right, bottom, left的值换一下,就又可以进行编码了!

image = face_recognition.load_image_file("Keanu Reeves.jpg")
face_locations = face_recognition.face_locations(image)

top, right, bottom, left= face_locations[0]

# face_image = image[top:bottom, left:right] # 不知道什么原因,改变尺寸后导致无法编码
face_image = image[0:100,0:100] # 在这里,将值调大调小都可以,只要不用原始face_locations的值
# face_image = face_image[:, :, ::-1]
face_encoding = face_recognition.face_encodings(face_image)
plt.imshow(face_image)

在这里插入图片描述

原因分析

**在图片裁剪时,使用的是地址引用的方式(软拷贝),而不是硬拷贝,导致裁剪前后的image其实共用了一个face_locations。**裁剪完后,只需要硬拷贝一次,形成新的image的地址,就可以解决。

因为在上面执行face_locations时,已经为image创建了一个内部的实例,
并且这个实例,关联到了之前的face_locations值, 如果是软拷贝的话,裁剪后的face_image与之前image指向了同一个地址。
这样直接传入给face_encodings()时,会将其一个optional的参数face_locations按照image的关联值带入,导致错误;
换不同尺寸去裁剪时,因为Python的动态内存机制,有可能Python会给face_image分配一个新的内存,只有分配一个新的内存情况,在下一步的face_encodings(new)中,才会将其当做一个新的图片处理,而不报错。
如果碰巧,裁剪的尺寸如果和face_locations接近时,就不会分配新的内存空间,在执行face-encodings()时带入旧的face_locations的值,而导致错误

软拷贝的情况:

使用分号裁剪软拷贝
共享
image_face_locations与new_image不匹配导致冲突
默认参数
image
image内存指针
地址传入face_locations函数
face_rec实例
image_face_locations
new_image
地址传入face_encodings函数

硬拷贝的情况:

裁剪后硬拷贝
入参
image
image内存指针
地址传入face_locations函数
face_rec实例
image_face_locations
new_image
new_image内存指针
face_encodings函数
新的face_rec实例
新的face_locations
新的face_encoding

解决办法

from PIL import Image, ImageDraw
import face_recognition
import matplotlib.pyplot as plt

image = face_recognition.load_image_file("Keanu Reeves.jpg")
face_locations = face_recognition.face_locations(image)

top, right, bottom, left= face_locations[0]
print(top, bottom, left, right)
face_image = image[top:bottom, left:right] # 不知道什么原因,改变尺寸后导致无法编码
# face_image = image[750:1682, 800:1575]

# new = face_image[:] # 这种软拷贝方式是不行的
'''
只能用下面这种硬拷贝方式才可以,因为在上面执行face_locations时,已经为image创建了一个内部的实例,
并且这个实例,关联到了之前的face_locations值, 如果是软拷贝的话,裁剪后的face_image与之前image指向了同一个地址。
这样直接传入给face_encodings()时,会将其一个optional的参数face_locations按照image的关联值带入,导致错误;
换不同尺寸去裁剪时,如果可能导致Python给face_image分配一个新的内存,只有分配一个新的内存,在下一步的face_encodings(new)中,才会
将其当做一个新的图片处理,而不报错。
如果碰巧,裁剪的尺寸如果和face_locations接近时,就不会分配新的内存空间,在执行face-encodings()时带入旧的face_locations的值,而导致错误
'''

new = face_image.copy()


face_encoding = face_recognition.face_encodings(new)

plt.imshow(face_image)

运行结果:
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/510197.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

深度解耦:使用Jetpack新技术Hilt实现依赖注入

注入解耦是一种软件设计模式,旨在将应用程序的不同组件解耦。通过采用依赖注入、控制反转、面向接口编程等技术,注入解耦模式可以帮助开发人员将应用程序分解为可重用和可扩展的组件。这样做可以减少代码的耦合度,提高模块化和可测试性&#…

Java并发编程实践学习笔记(三)——共享对象之发布和异常

目录 1 公共静态变量逸出 2 非私有方法逸出私有变量 3 this引用逸出 4 构造函数中的可覆盖方法调用逸出 发布(publishing)一个对象的意思是:使对象能够在当前作用域之外的代码中使用。例如,将一个指向该对象的引用保存到其他代…

奖品收到了

质量一流!物流速度快!下次继续努力! 开心

抽象、封装、继承、多态

抽象 抽象是从众多的事物中抽取出共同的、本质性的特征,而舍弃其非本质的特征的过程。 下面是抽象到封装的过程 如果不考虑实际的情况下 人的定义:有嘴、有脚、有眼睛、有耳朵、会吃饭、会跑。 动物的定义:有嘴、有脚、有眼睛、有耳朵、会…

2023年网红经济研究报告

第一章 行业概况 随着社交媒体和移动互联网的普及,网红经济迅速崛起。网红经济,是指以网络为平台,通过网红的影响力、热度和传播力,形成的一种以流量变现为主的商业模式。网红经济涉及到的行业非常广泛,如美妆、时尚、…

ai聊天机器人chatgpt收费版

AI聊天机器人的功能通常包括以下几个方面: 自然语言理解。该功能可以识别并理解用户输入的自然语言,如文本、语音等,以便进行后续的处理和回复。 对话管理。该功能可以管理对话的上下文和流程,并根据用户的输入和意图来产…

Linux系统查看CPU信息命令cat /proc/cpuinfo详细说明

Linux操作系统服务器如何查看CPU处理器信息?使用命令cat /proc/cpuinfo可以查看CPU详细信息,包括CPU核数、逻辑CPU、物理CPU个数、CPU是否启用超线程等,阿里云服务器网分享Linux服务器查看CPU信息命令: 目录 Linux服务器查看CPU…

JavaWeb12-三大组件之监听器-Listener

1. 官方文档 文档:java_ee_api_中英文对照版.chm 2. Listener 监听器介绍 Listener 监听器它是 JavaWeb 的三大组件之一。JavaWeb 的三大组件分别是:Servlet 程序、Listener 监听器、Filter 过滤器Listener 是 JavaEE 的规范,就是接口监听…

(附源码)计算机毕业设计Java动物在线领养网站

项目运行 🍅包售后,包调试,包讲解🍅 🍅获取方式1:文章末尾获取联系🍅 🍅获取方式2:点我进入,文章末尾获取联系🍅 🍅包售后,包调试,包讲…

WX小程序 - 2

条件渲染: wx:if "{{ newlist.length 0 }}" wx:else 跳路由:绑定点击事件,执行跳转页面 bindtap data-id"{{ item.id }}" 添加id wx.navigateTo 跳路由并传参, 下一个路由 onLoad生命周期可以获得参数…

每周一算法:前缀和

前缀和 前缀和可以理解为数列的前 n 项的和。它通过预处理的方式,能够快速查询序列中从第L个数到到第R个数的和。 算法思想 其基本思想是在原序列的基础上预处理一个前缀和数组 s [ ] s[] s[],其中 s [ i ] s[i] s[i]表示序列前 i i i个数的和。通过前…

Exception in thread “main“ java.lang.UnsupportedClassVersionError

java MainDemo执行main方法报错 Error: A JNI error has occurred, please check your installation and try again Exception in thread "main" java.lang.UnsupportedClassVersionError: MainDemo has been compiled by a more recent version of the Java Runtime…

多台电脑共享鼠标键盘软件

背景 最近接手了2个不同base的项目,由于2个base的不同代码加密管理,必须要用两台电脑进行分别开发。于是,我不大的办公桌上要摆上2个键盘和2个鼠标,一下子就显得桌面特别杂乱,办公心情都不舒畅了。 我跟朋友吐槽了这件…

用LeangooScrum敏捷工具做缺陷管理和迭代规划和迭代执行

上一篇我们介绍了如何管理产品路线图(用Leangoo领歌Scrum敏捷开发工具管理产品路线图?_哆啦B梦_的博客-CSDN博客)和敏捷需求管理(使用敏捷开发工具做敏捷需求管理流程_哆啦B梦_的博客-CSDN博客) 这一篇我们介绍下如何用Scrum敏捷…

纷享销客携手百捷、锐之旗走进湖南竞网,探索互联网营销创新

近日,《互联网营销创新增长路径-高管面对面闭门会》在长沙成功举办,活动邀请武汉百捷集团股份有限公司、河南锐之旗信息技术有限公司,两家互联网营销服务头部企业的高层走进湖南竞网数字科技集团有限公司(以下简称“竞网”&#x…

[CSDN] 512创作纪念日,大处着眼,小处着手,乐观进取

大家好,我是一名程序员,也是一名CSDN博客作者,今天是我成为CSDN博客作者的512天纪念日,我想借此机会和大家分享一下我的创作历程。 初心与动力 从事IT行业多年,我深深感受到这个行业变化的速度非常之快,需…

责任链模式——使编程更有灵活性

● 责任链模式介绍 责任链模式(Iterator Pattern),是行为型设计模式之一。什么是“链”?我们将多个节点首位相连构成的模型称为链,比如生活中常见的锁链,就是由一个个圆角长方形的铁环串起来的结构。对于链式结构&…

浅谈绿色创新型校园的节约能耗与能耗管理的应用

摘要:保护地球资源和环境的可持续发展理论成为我国的基本国策。建筑节能上升到较高地位。仅有能量的“守恒”是不够的,更要研究用*小代价和*小能耗来满足人们的而合理需求,实现建筑合理用能。文章主要针对学校能源管理的问题进行研究&#xf…

带你简单了解Chatgpt背后的秘密:大语言模型所需要条件(数据算法算力)以及其当前阶段的缺点局限性

带你简单了解Chatgpt背后的秘密:大语言模型所需要条件(数据算法算力)以及其当前阶段的缺点局限性 1.什么是语言模型? 大家或多或少都听过 ChatGPT 是一个 LLMs,那 LLMs 是什么?LLMs 全称是 Large Language…

TomcatServletHTTP

1、Web概述 1.1 Web相关概念 Web是全球广域网,也称为万维网(www),能够通过浏览器访问的网站。 在我们日常的生活中,经常会使用浏览器去访问百度、京东、传智官网等这些网站,这些网站统称为Web网站。 如下就是通过浏览器访问传智…