人体分割模型ACE2P与M2FP,解析人脸人体各部件属性,语义化分析

news2025/7/10 17:05:14

前言

在做某任务的时候,需要对人物图片进行预处理。

预处理的要求就是要将图片中的人物各部件分割出来,标识为各种不同颜色,比如脸部为蓝色,脖颈部位绿色,其他地方为红色

最初任务使用的PaddleSeg中基于CelebAMask-HQ数据集的BiSeNet-v2和PP_LiteSeg模型,以及同样基于该数据集的BiSeNet模型,效果呢,人脸部分分割得确实还可以,但是遇到复杂的头发、头饰、服装的时候,效果就一言难尽了。

基于此情况,又调研了ACE2P和M2FP,分别是大厂百度和阿里的,其分割效果还是很好,基本满足我的预处理需求。

ACE2P虽然优秀,但是在效果图来看其竟然没有脖子!他实际上是把下巴下部的皮肤统一纳入脸部范畴,但是其分割的时候又把这部分信息丢失了!
ACE2P没有脖子!!!
为了解决没脖子的问题,又引入了M2FP模型,思路是将M2FP解析出来的脖子部分的给填充到ACE2P的结果图中。

另外,ACE2P默认的解析部件的着色不是我们期望的颜色,这里还要对其渲染颜色进行修改。

思路拟定,开干:

ACE2P

百度原介绍:

人体解析(Human Parsing)是细粒度的语义分割任务,其旨在识别像素级别的人类图像的组成部分(例如,身体部位和服装)。

ACE2P通过融合底层特征,全局上下文信息和边缘细节,端到端地训练学习人体解析任务。该结构针对Intersection over Union指标进行针对性的优化学习,提升准确率。

以ACE2P单人人体解析网络为基础的解决方案在CVPR2019第三届LIP挑战赛中赢得了全部三个人体解析任务的第一名。该PaddleHub Module采用ResNet101作为骨干网络,接受输入图片大小为473x473x3。

地址:Paddle Hub

安装ACE2P依赖

!pip install paddlepaddle -i https://mirror.baidu.com/pypi/simple
!pip install paddlehub -i https://mirror.baidu.com/pypi/simple
!pip install matplotlib
!pip install Pillow

#为了解决colab中libssl.os报错的问题
%cd /content/drive/MyDrive
!wget http://nz2.archive.ubuntu.com/ubuntu/pool/main/o/openssl/libssl1.1_1.1.1f-1ubuntu2.19_amd64.deb
!sudo dpkg -i libssl1.1_1.1.1f-1ubuntu2.19_amd64.deb

ACE2P效果


import matplotlib.image as mpimg
from matplotlib.pylab import plt

# 解析前展示原图
test_img_path = "/content/155.jpg"
img = mpimg.imread(test_img_path)
plt.imshow(img)
plt.axis('off')
plt.show()

#--------------------------------------
import paddlehub as hub
import matplotlib.pyplot as plt

image=mpimg.imread(test_img_path)
module = hub.Module(name="ace2p")
results = module.segmentation(images = [image],
                output_dir = '/content/ace2p_output/',
                visualization = True)
print(f'解析结果:{results}')
path = results[0]['path'][:-3]
print(path+'png')


img = mpimg.imread('/content/ace2p_output/'+path+'png')
plt.imshow(img)
plt.axis('off')
plt.show()

效果图:
在这里插入图片描述

ACE2P修改解析图颜色

  • 源码在modules/image/semantic_segmentation/ace2p/module.py中
  • 进行解析的核心方法在PaddleHub/modules/image/semantic_segmentation/ace2p
    /processor.py中postprocess()方法
  • postprocess方法最后一个参数palette指明各个部位的颜色数值,该参数默认是在实例化ACE2P类的调用的processor.py的get_palette方法
  • 方法入参num_cls是读取的label_list.txt中行的个数,也就是为每行数据构建一个颜色值,返回。
    get_palette方法源码:
def get_palette(num_cls):
    """
    Returns the color map for visualizing the segmentation mask.

    Args:
        num_cls: Number of classes

    Returns:
        The color map
    """
    n = num_cls
    palette = [0] * (n * 3)
    for j in range(0, n):
        lab = j
        palette[j * 3 + 0] = 0
        palette[j * 3 + 1] = 0
        palette[j * 3 + 2] = 0
        i = 0
        while lab:
            palette[j * 3 + 0] |= (((lab >> 0) & 1) << (7 - i))
            palette[j * 3 + 1] |= (((lab >> 1) & 1) << (7 - i))
            palette[j * 3 + 2] |= (((lab >> 2) & 1) << (7 - i))
            i += 1
            lab >>= 3
    return palette

modules/image/semantic_segmentation/ace2p/label_list.txt原始内容:

background
Hat
Hair
Glove
Sunglasses
UpperClothes
Dress
Coat
Socks
Pants
Jumpsuits
Scarf
Skirt
Face
Left-arm
Right-arm
Left-leg
Right-leg
Left-shoe
Right-shoe
  • 所以,替换颜色的方法就是替换module.palette的值即可。
import paddlehub as hub
import matplotlib.pyplot as plt


image=mpimg.imread("/content/155.jpg")

#ace2p 模型
module = hub.Module(name="ace2p")
#替换绘制颜色为自己需要的颜色,背景:白色,头发+脸+耳朵:蓝色,脖子:绿色,衣服:红色
new_palette_dic = {
    "background": [255,255,255],#白色
    "Hat": [0,0,255], #蓝色
    "Hair": [0,0,255],
    "Glove": [255,0,0], #红色
    "Sunglasses": [0,0,255],
    "UpperClothes": [255,0,0],
    "Dress": [255,0,0],
    "Coat": [255,0,0],
    "Socks": [255,0,0],
    "Pants": [255,0,0],
    "Jumpsuits": [255,0,0],
    "Scarf": [0,255,0],#绿色
    "Skirt": [255,0,0],
    "Face": [0,0,255],
    "Left-arm": [255,0,0],
    "Right-arm": [255,0,0],
    "Left-leg": [255,0,0],
    "Right-leg": [255,0,0],
    "Left-shoe": [255,0,0],
    "Right-shoe": [255,0,0],
}
new_palette=[]
for v in new_palette_dic.values():
    new_palette.append(v[0])
    new_palette.append(v[1])
    new_palette.append(v[2])
module.palette=new_palette


results = module.segmentation(images = [image],
                output_dir = '/content/ace2p_output/',
                visualization = True)
print(f'results:{results}')
print('---------------')

path = results[0]['path'][:-3]
print('文件名:'+path+'png')


img = mpimg.imread('/content/ace2p_output/'+path+'png')
plt.imshow(img)
plt.axis('off')
plt.show()

效果图:
在这里插入图片描述

M2FP

介绍:

M2FP(Mask2Former for Parsing,官方代码)基于 Mask2Former 架构,并进行了一些改进以适应人体解析。 M2FP 可以适应几乎所有人体解析任务并产生惊人的性能。
M2FP多人人体解析模型
注意:这里使用的是M2FP多人人体解析模型。

安装依赖

#先安装必要库
%cd /content/drive/MyDrive
!pip install /content/drive/MyDrive/torch_scatter-2.1.2+pt20cu118-cp310-cp310-linux_x86_64.whl
!pip install -U openmim
!mim install mmcv
#再安装依赖
!pip install antlr4-python3-runtime
!pip install modelscope
!pip install "modelscope[cv]" -f https://modelscope.oss-cn-beijing.aliyuncs.com/releases/repo.html

运行效果

from modelscope.outputs import OutputKeys
from modelscope.pipelines import pipeline
from modelscope.utils.constant import Tasks

import imageio
from PIL import Image
import numpy as np
import matplotlib.image as mpimg
import matplotlib.pyplot as plt


input_img = r'/content/155.jpg'
segmentation_pipeline = pipeline(Tasks.image_segmentation, 'damo/cv_resnet101_image-multiple-human-parsing')
result = segmentation_pipeline(input_img)
#print(f'结果:{result}')
#print(result[OutputKeys.LABELS])

labels = result[OutputKeys.LABELS]
masks=result['masks']

#获取人脸
face = Image.fromarray(masks[labels.index('Face')]*255).convert("RGB")
face.save('/content/face-1.jpg')
w = face.width
h = face.height
#创建画布底图,白色底
img = Image.new("RGB",(w,h),(255,255,255))

#获取头发
hair=Image.fromarray(masks[labels.index('Hair')]*255).convert("RGB")
#获取脖子
neck=Image.fromarray(masks[labels.index('Torso-skin')]*255).convert("RGB")
#获取衣服
clothes=Image.fromarray(masks[labels.index('UpperClothes')]*255).convert("RGB")

def is_target(target,x,y):
    r, g, b = target.getpixel((x, y))
    #如果是白色,则说明是目标区域
    if (r>0 and r<255) or (g>0 and g<255) or (b>0 and b<255):
      print(f'该位置不是纯白色:{x},{y},color:({r},{b},{b})')
    return r==255 and g==255 and b==255

def change_bg_color(x,y,colors):
    img.putpixel((x,y),(colors[0],colors[1],colors[2]))


#迭代每一个像素点,在底图上绘制出对应的人脸部位
for x in range(w):
    for y in range(h):
        #判断是否为头发或者脸部区域
        if is_target(hair,x,y) or is_target(face,x,y):
            #底图上要绘制为蓝色
            change_bg_color(x,y,[0,0,255])
        #判断是否为脖子区域
        elif is_target(neck,x,y):
            #底图要绘制为绿色
            change_bg_color(x,y,[0,255,0])
        #判断是否为衣服区域
        elif is_target(clothes,x,y):
            #底图要绘制为绿色
            change_bg_color(x,y,[255,0,0])
img.save('/content/m2fp-test3.jpg')
img2 = mpimg.imread('/content/m2fp-test3.jpg')
plt.imshow(img2)
plt.axis('off')
plt.show()

效果如图:
脖子终于卡出来了!

M2FP多图测试

from modelscope.outputs import OutputKeys
from modelscope.pipelines import pipeline
from modelscope.utils.constant import Tasks

import imageio 
from PIL import Image
import numpy as np
import os


segmentation_pipeline = pipeline(Tasks.image_segmentation, 'damo/cv_resnet101_image-multiple-human-parsing')

def is_target(target,x,y):
    r, g, b = target.getpixel((x, y))
    #如果是白色,则说明是目标区域
    return r==255 and g==255 and b==255

def change_bg_color(img,x,y,colors):
    img.putpixel((x,y),(colors[0],colors[1],colors[2]))

def get_item(masks,labels,label):
    if label in labels:
        iis=[i for i, x in enumerate(labels) if x==label]        
        imgs=[None]*len(iis)
        for i,v in enumerate(iis):
            imgs[i]=Image.fromarray(masks[v]*255).convert("RGB")
        return imgs
    else:
        return []
    
    
for t in os.listdir('./test-jpg/'):
    if not t.endswith('.jpg'):
        continue
    result = segmentation_pipeline(os.path.join('./test-jpg/',t))
    
    labels = result[OutputKeys.LABELS]
    print(f'{t}--->{labels}')
    masks=result['masks']

    #获取人脸
    face = Image.fromarray(masks[labels.index('Face')]*255).convert("RGB")
    w = face.width
    h = face.height
    print(f'底图宽{w},高{h}')
    #创建画布底图,白色底
    img = Image.new("RGB",(w,h),(255,255,255))


    
    #获取头发
    hairs=get_item(masks,labels,'Hair')
    #获取脖子
    neck=Image.fromarray(masks[labels.index('Torso-skin')]*255).convert("RGB")
    #获取衣服
    clothes=get_item(masks,labels,'UpperClothes')
    #手臂,不一定有
    LeftArm=get_item(masks,labels,'Left-arm')
    RightArm=get_item(masks,labels,'Right-arm')
    #外套,不一定有
    Coats=get_item(masks,labels,'Coat')
    #太阳镜,不一定有
    Sunglasses = get_item(masks,labels,'Sunglasses')
    #围巾,不一定有    
    Scarf=get_item(masks,labels,'Scarf')
    #裙子,不一定有
    Skirt=get_item(masks,labels,'Skirt')
    #裤子,不一定有
    Pants=get_item(masks,labels,'Pants')
    #连衣裙,不一定有
    Dress=get_item(masks,labels,'Dress')
    
    

    #迭代每一个像素点,在底图上绘制出对应的人脸部位
    print(f'2底图宽{w},高{h}')
    for x in range(w):
        for y in range(h):            
            #判断是否为头发或者脸部区域
            for ha in hairs:                
                if is_target(ha,x,y):
                    #底图上要绘制为蓝色
                    change_bg_color(img,x,y,[0,0,255])
            if is_target(face,x,y):
                change_bg_color(img,x,y,[0,0,255])
            #判断是否为脖子区域
            if is_target(neck,x,y):
                #底图要绘制为绿色
                change_bg_color(img,x,y,[0,255,0])
            #判断是否为衣服区域
            for c in clothes:
                if is_target(c,x,y):
                    #底图要绘制为红色
                    change_bg_color(img,x,y,[255,0,0])
            #不一定有的其他部分
            for i in LeftArm:
                if is_target(i,x,y):
                    change_bg_color(img,x,y,[255,0,0])
            for i in RightArm:
                if is_target(i,x,y):
                    change_bg_color(img,x,y,[255,0,0])
            for i in Coats:
                if is_target(i,x,y):
                    change_bg_color(img,x,y,[255,0,0])
            for i in Sunglasses:
                if is_target(i,x,y):
                    change_bg_color(img,x,y,[0,0,255])
            for i in Scarf:
                if is_target(i,x,y):
                    change_bg_color(img,x,y,[255,0,0])
            for i in Skirt:
                if is_target(i,x,y):
                    change_bg_color(img,x,y,[255,0,0])
            for i in Pants:
                if is_target(i,x,y):
                    change_bg_color(img,x,y,[255,0,0])
            for i in Dress:
                if is_target(i,x,y):
                    change_bg_color(img,x,y,[255,0,0])
            
            
                

    img.show()
    #存储为高质量的、无压缩的jpg
    img.save('./test-jpg/results/'+t,quality=100,subsampling=0)

阿富汗少女
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

结论

在多图综合比较之下,ACE2P虽然速度占优,但是精确度不及M2FP。

所以最终任务直接使用M2FP模型进行处理。

不过由于要进行每个像素的检查,代码运行确实够慢的!

最终渲染图部件与部件之间还存在空白问题需要优化!

速度优化

m2fp解析出来之后,对解析的结果按背景图的长和宽进行了每个像素的迭代判断操作,实际运行下来速度超慢!

所以这里就对这部分逻辑进行速度优化

基本思路为:解析结果是一个二维array,每种子array的值只可能为[0,0,0]或[255,255,255],所以我们构建一个和背景一样长和宽的二维数组,填充[255,255,255],依次寻找各个人体组件中所有值不为[0,0,0]的元素,将这些元素替换为对应的RGB值,再将背景中同样下标的元素的值替换为该值,这样就相当于把背景中的需要调整的像素点的RGB都调整到位了,然后再输出为图片即可。

上代码:

import math
import os

import configargparse
import numpy as np
from PIL import Image
from modelscope.outputs import OutputKeys
from modelscope.pipelines import pipeline
from modelscope.utils.constant import Tasks
from tqdm import tqdm


def partition_list(arr, m):
    """split the list 'arr' into m pieces"""
    n = int(math.ceil(len(arr) / float(m)))
    return [arr[i:i + n] for i in range(0, len(arr), n)]


def is_target(target, x, y):
    r, g, b = target.getpixel((x, y))
    # 如果是白色,则说明是目标区域
    return r == 255 and g == 255 and b == 255


def change_bg_color(img, x, y, colors):
    img.putpixel((x, y), (colors[0], colors[1], colors[2]))


def get_item(masks, labels, label):
    if label in labels:
        iis = [i for i, x in enumerate(labels) if x == label]
        arrs = [None] * len(iis)
        for i, v in enumerate(iis):
            arrs[i] = masks[v] * 255
        return arrs
    else:
        return []


def replace_bgArray_item(bgArray, targets, newArray):
    '''将指定的背景二维数组中寻找到的值不为0的位置的子数组,替换为newArray数组'''
    for tar in targets:
        indexs = np.where(tar != 0)
        for index in zip(*indexs):  # index的值为(1,1,1),表示第一行第一列的第一个元素
            bgArray[(index[0], index[1])] = newArray
    return bgArray


def predict(input_dir, save_dir):
    '''使用达摩M2FP多人人体解析模型进行人体语义解析'''

    img_lists = os.listdir(input_dir)

    segmentation_pipeline = pipeline(Tasks.image_segmentation, 'damo/cv_resnet101_image-multiple-human-parsing')
    print("M2FP模型开始人体解析...")
    bgImg = None
    for t in tqdm(img_lists, desc='解析进度'):
        if not t.endswith('.jpg') and not t.endswith('.png'):
            continue
        # 读取一张图片,根据其宽高创建背景图
        if bgImg is None:
            w, h = Image.open(os.path.join(input_dir, t)).size
            # 构建一个w行h列有3个值的二维数组,每个子数组的值为(255, 255, 255),即填充白色,作为背景图
            bgImg = np.full((w, h, 3), (255, 255, 255))
        # copy一份背景,作为本次解析的背景图
        myBgArray = bgImg.copy()

        # 进行语义分割
        result = segmentation_pipeline(os.path.join(input_dir, t))
        # 得到语义结果
        labels = result[OutputKeys.LABELS]
        masks = result['masks']
        # 获取人脸
        face = masks[labels.index('Face')] * 255
        # 获取头发
        hairs = get_item(masks, labels, 'Hair')
        # 获取脖子
        neck = masks[labels.index('Torso-skin')] * 255
        # 获取衣服
        clothes = get_item(masks, labels, 'UpperClothes')
        # 手臂,不一定有
        LeftArm = get_item(masks, labels, 'Left-arm')
        RightArm = get_item(masks, labels, 'Right-arm')
        # 外套,不一定有
        Coats = get_item(masks, labels, 'Coat')
        # 太阳镜,不一定有
        Sunglasses = get_item(masks, labels, 'Sunglasses')
        # 围巾,不一定有
        Scarf = get_item(masks, labels, 'Scarf')
        # 裙子,不一定有
        Skirt = get_item(masks, labels, 'Skirt')
        # 裤子,不一定有
        Pants = get_item(masks, labels, 'Pants')
        # 连衣裙,不一定有
        Dress = get_item(masks, labels, 'Dress')

        # 在背景上绘制蓝色人脸
        myBgArray = replace_bgArray_item(myBgArray, [face], [0, 0, 255])
        # 头发 蓝色
        myBgArray = replace_bgArray_item(myBgArray, hairs, [0, 0, 255])
        # 脖子 绿色
        myBgArray = replace_bgArray_item(myBgArray, [neck], [0, 255, 0])
        # 获取衣服等等 以下均为红色
        myBgArray = replace_bgArray_item(myBgArray, clothes, [255, 0, 0])
        myBgArray = replace_bgArray_item(myBgArray, LeftArm, [255, 0, 0])
        myBgArray = replace_bgArray_item(myBgArray, RightArm, [255, 0, 0])
        myBgArray = replace_bgArray_item(myBgArray, Coats, [255, 0, 0])
        myBgArray = replace_bgArray_item(myBgArray, Sunglasses, [255, 0, 0])
        myBgArray = replace_bgArray_item(myBgArray, Scarf, [255, 0, 0])
        myBgArray = replace_bgArray_item(myBgArray, Skirt, [255, 0, 0])
        myBgArray = replace_bgArray_item(myBgArray, Pants, [255, 0, 0])
        myBgArray = replace_bgArray_item(myBgArray, Dress, [255, 0, 0])

        # 将背景数组myBgArray存储为高质量的、无压缩的jpg
        bg = Image.fromarray(myBgArray.astype(np.uint8))
        bg.save(os.path.join(save_dir, t), quality=100, subsampling=0)
    print(f"解析完成,结果存储于:{save_dir}")


if __name__ == "__main__":
    parser = configargparse.ArgumentParser()
    parser.add_argument('--input_dir', type=str, default='./inputImgs', help='待解析的图片目录路径')
    parser.add_argument('--save_dir', type=str, default='./outputImgs/', help='解析完成后的图片目录存储路径')
    args = parser.parse_args()
    predict(input_dir=args.input_dir, save_dir=args.save_dir)

实际跑了一下,速度还满意!

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

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

相关文章

C# RestoreFormer 图像(人脸面部)修复

效果 项目 代码 using Microsoft.ML.OnnxRuntime; using Microsoft.ML.OnnxRuntime.Tensors; using OpenCvSharp; using System; using System.Collections.Generic; using System.Drawing; using System.Drawing.Imaging; using System.Windows.Forms;namespace 图像修复 {pu…

优维低代码实践:片段

优维低代码技术专栏&#xff0c;是一个全新的、技术为主的专栏&#xff0c;由优维技术委员会成员执笔&#xff0c;基于优维7年低代码技术研发及运维成果&#xff0c;主要介绍低代码相关的技术原理及架构逻辑&#xff0c;目的是给广大运维人提供一个技术交流与学习的平台。 优维…

Unity3D 基础——使用 Vector3.Distance 计算两个物体之间的距离

Vector3-Distance - Unity 脚本 APIhttps://docs.unity.cn/cn/current/ScriptReference/Vector3.Distance.html 1.在场景中新建两个 Cube 立方体&#xff0c;在 Scene 视图中将两个 Cude的位置错开。 2.新建 C# 脚本 Distance.cs&#xff08;写完记得保存&#xff09; using …

PS 学习笔记

书籍&#xff1a;Photoshop 2022从入门到精通-敬伟-微信读书 1. PS 常用快捷键 复位右侧基本工作栏&#xff1a;【窗口】-【工作区】- 【复位基本功能】 Ctrl 鼠标滚轮&#xff1a;主界面图片左右滚动Shift 鼠标滚轮&#xff1a;主界面图片上下滚动Alt 鼠标滚轮&#xff1…

StarUML的介绍与使用

文章目录 简介视图StarUML创建视图类图用例图时序图 简介 UML&#xff1a;统一建模语言&#xff0c;用模型元素组成的不同视图从各个维度来描述系统 StarUML为常用系统建模工具之一 视图 常见视图的概念可参考&#xff1a;UML常见的几种视图 包括&#xff1a;用例图、顺序图…

联想G50笔记本直接使用F键功能(F1~F12)需要在BIOS设置关闭热键功能可以这样操作!

如果开启启用热键模式按F1就会出现FnF1的效果&#xff0c;不喜欢此方式按键的用户可以进入BIOS设置界面停用热键模式即可。 停用热键模式方法如下&#xff1a; 1、重新启动笔记本电脑&#xff0c;当笔记本电脑屏幕出现Lenovo标识的时候&#xff0c;立即按FnF2进入BIOS设置界面…

ssm+vue的养老院老人健康监护平台(有报告)。Javaee项目,ssm vue前后端分离项目。

演示视频&#xff1a; ssmvue的养老院老人健康监护平台&#xff08;有报告&#xff09;。Javaee项目&#xff0c;ssm vue前后端分离项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系…

从入门到进阶 之 ElasticSearch 节点配置 集群篇

&#x1f339; 以上分享 ElasticSearch 安装部署&#xff0c;如有问题请指教写。&#x1f339;&#x1f339; 如你对技术也感兴趣&#xff0c;欢迎交流。&#x1f339;&#x1f339;&#x1f339; 如有需要&#xff0c;请&#x1f44d;点赞&#x1f496;收藏&#x1f431;‍&a…

基于SSM+Vue的咖啡销售系统

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;Vue 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#xff1a;是 目录…

全面中文大语言模型评测来啦!香港中文大学最新研究

ChatGPT 的一声号角吹响了2023年全球大语言模型的竞赛。 2023年初以来&#xff0c;来自工业界和研究机构的各种大语言模型层出不穷&#xff0c;特别值得一提的是&#xff0c;中文大语言模型也如雨后春笋般&#xff0c;在过去的半年里不断涌现。 与此同时&#xff0c;和如何训…

Android 10 中的隐私权变更

Android 10 中的隐私权变更 重大变更外部存储访问权限范围限定为应用文件和媒体在后台运行时访问设备位置信息需要权限以 Android 9 或更低版本为目标平台时自动授予访问权限在设备升级到 Android 10 后访问针对从后台启动 Activity 的限制标识符和数据移除了联系人亲密程度信息…

Go语言入门心法(六): HTTP面向客户端|服务端编程

Go语言入门心法(一): 基础语法 Go语言入门心法(二): 结构体 Go语言入门心法(三): 接口 Go语言入门心法(四): 异常体系 Go语言入门心法(五): 函数 一:go语言面向web编程认知 Go语言的最大优势在于并发与性能,其性能可以媲美C和C,并发在网络编程中更是至关重要 使用http发送请…

hal开发之hidl/aidl支持的绑定式直通式详细讲解

为啥有hidl呢&#xff1f; 这个问题其实网络上答案比较多&#xff0c;属于android想要让厂商快速升级解耦制定的&#xff0c;即把原来系统framework和厂商耦合的hal在同一个个system.img进行剥离开&#xff0c;把厂商相关的放到vendor.img&#xff0c;aosp系统公共部分framewo…

ros_rtsp订阅Image类型topic转换为rtsp视频流

文章目录 一、安装环境二、在catkin工作空间中构建三、设置流四、推出视频流五、验证视频流1、安装vlc拉流2、安装gstreamer拉流3、安装FFmpeg拉流 一、安装环境 ROS gstreamer development libs&#xff0c;包括base、good、bad和rtspserver: sudo apt-get install libgstre…

成功实施自动化测试的优点

目录 什么是自动化测试&#xff1f; 自动化测试的好处 测试执行7*24 回归测试 可重用性 节省您很多时间 降低成本更好地利用人力 左移测试做得更好&#xff01; 解放手动测试 最大化测试覆盖率 监控服务 复杂而冗长的测试方案 结论 随着技术的发展&#xff0c;保证…

国产FiRa认证低功耗UWB系统级SoC精准定位方案芯片

目录 什么是"UWB技术"国产UWB方案芯片特性国产低功耗UWB SoC芯片特性 随着物联网、无线通信等技术的不断发展&#xff0c;UWB作为一种超宽带通信技术&#xff0c;逐渐在精准定位、智能家居、汽车电子、智能制造等领域崭露头角。 什么是"UWB技术" UWB&…

Python接口自动化测试之Requests库Pytest框架

发送get请求 #导包 import requests #定义一个url url "http://xxxxxxx" #传递参数 payload"{\"head\":{\"accessToken\":\"\",\"lastnotice\":0,\"msgid\":\"\"},\"body\":{\"…

C#简单晶圆wafermapping显示示范demo

点击&#xff0c;双击可改变颜色 预设5行8列数据&#xff1a; using (fratte.at.WafermapDisplay.Form1 form_show new fratte.at.WafermapDisplay.Form1()){int[,] data_demo new int[,]{{ 0,0,0,1,0 },{ 0,5,1,0,0 },{ 1,7,6,2,3 },{ 1,0,1,2,3 },{ 0,2,0,2,3 }, { 1,5,6,…

SpringCloud: feign整合sentinel实现降级

一、加依赖&#xff1a; <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache…

软件测试用例设计方法-因果图法

边界值法是等价类划分法的补充&#xff0c;所以&#xff0c;它们是一对搭档。 那么&#xff0c;判定表法有没有它的搭档呢&#xff1f; 答案是&#xff0c;有的。那就是本篇文章分享的用例设计方法—— 因果图法 。 定义 因果图法&#xff1a; 用来处理等价类划分和边界值考…