【图像算法】马赛克识别

news2024/11/17 23:59:41

【目的】

校验视频中出现马赛克的频率,抽象成将视频切割成图片,对每张代测图片进行自动化验证。

【实现】

图像边缘检测算法识别

算法步骤:

  1. 使用高斯滤波器,以平滑图像,滤除噪声。
  2. 计算图像中每个像素点的梯度强度和方向。
  3. 应用非极大值(Non-Maximum Suppression)抑制,以消除边缘检测带来的杂散响应。
  4. 应用双阈值(Double-Threshold)检测来确定真实的和潜在的边缘。
  5. 通过抑制孤立的弱边缘最终完成边缘检测。

八点法计算方案

说明:像素点处理方法,缺点是一张图片的处理速度过慢,平均在5,6s/张图

算法步骤:

  1. 对图片进行Canny边缘检测,阈值分别取40和200,得到图像的检测结果;

在这里插入图片描述

  1. 其中马赛克区域经过边缘检测后,出现了一堆方块状或类方块状的区域;
    在这里插入图片描述

  2. 方块和类方块大体分为以上5种,分别为完备的正方形、分别缺一边的不完备正方形。为了统计上述边缘检测结果图中含有的这5类正方形,可以采取下述方式进行统计:

  3. 边长从3开始,逐次加1,到33截止(这里有待考究)。判断每个像素以这个边长能否组成正方形(5种情况,以下简称正方形)。如果能,这个边长的正方形数加1,如果不能继续遍历。

  • 整体判断法:以此边长遍历整个正方形区域,如果无缺失的像素/整个正方形的像素大于70%,认为这个正方形存在。这种方法的优点是判断准确,综合利用正方形所有的像素,但缺点同样明显,运算速度极低;
  • 八点判断法:选取正方形中的八个点来进行判断,如果选择的八个点都满足构成正方形条件,那么,认为此正方形存在。这种方法的优点是运算速度有所提升,但是准确率上存在不足;****
  • 四点判断法:选取正方形上的四个点位置进行判断,如果选择的四个点都满足构成正方的条件,认为此正方形存在。这种方法运算速度最快,伴随着的是不太理想的准确率。

图像轮廓计算正方形面积

识别正方形
area = cv2.contourArea(obj) #计算轮廓内区域的面积

机器学习-图片分类
https://github.com/search?q=detect+mosaic&type=

机器学习-马赛克识别
https://github.com/search?q=detect+mosaic&type=

【代码1】

import cv2
from PIL import Image
import numpy as np
import math
import warnings
import os
from numpy import sort
import time

make_file_cmd = "touch test_mosaic_tmp.txt"
os.popen(make_file_cmd).read()
file = open('./test_mosaic_tmp.txt', 'w', encoding='utf-8')

# 算法来源,博客https://www.cnblogs.com/techyan1990/p/7291771.html和https://blog.csdn.net/zhancf/article/details/49736823
"""
8点法确认正方形
"""

def test_mosaic(url):
    highhold = 100  # 高阈值
    lowhold = 60  # 低阈值

    warnings.filterwarnings("ignore")
    demo = Image.open(url)
    im = np.array(demo.convert('L'))  # 灰度化矩阵
    # im = cv2.imread(url, 0)
    # image = cv2.Canny(im, 100, 200, 5)
    # file.write(str(im.shape) + "\n")

    height = im.shape[0]  # 尺寸
    width = im.shape[1]
    gm = [[0 for i in range(width)] for j in range(height)]  # 梯度强度
    gx = [[0 for i in range(width)] for j in range(height)]  # 梯度x
    gy = [[0 for i in range(width)] for j in range(height)]  # 梯度y

    theta = 0  # 梯度方向角度360度
    dirr = [[0 for i in range(width)] for j in range(height)]  # 0,1,2,3方位判定值
    highorlow = [[0 for i in range(width)] for j in range(height)]  # 强边缘、弱边缘、忽略判定值2,1,0
    rm = np.array([[0 for i in range(width)] for j in range(height)])  # 输出矩阵
    # 高斯滤波平滑,3x3
    for i in range(1, height - 1, 1):
        for j in range(1, width - 1, 1):
            rm[i][j] = im[i - 1][j - 1] * 0.0924 + im[i - 1][j] * 0.1192 + im[i - 1][j + 1] * 0.0924 + im[i][
                j - 1] * 0.1192 + im[i][j] * 0.1538 + im[i][j + 1] * 0.1192 + im[i + 1][j - 1] * 0.0924 + im[i + 1][
                           j] * 0.1192 + im[i + 1][j + 1] * 0.0924
    for i in range(1, height - 1, 1):  # 梯度强度和方向
        for j in range(1, width - 1, 1):
            gx[i][j] = -rm[i - 1][j - 1] + rm[i - 1][j + 1] - 2 * rm[i][j - 1] + 2 * rm[i][j + 1] - rm[i + 1][j - 1] + \
                       rm[i + 1][j + 1]
            gy[i][j] = rm[i - 1][j - 1] + 2 * rm[i - 1][j] + rm[i - 1][j + 1] - rm[i + 1][j - 1] - 2 * rm[i + 1][j] - \
                       rm[i + 1][j + 1]
            gm[i][j] = pow(gx[i][j] * gx[i][j] + gy[i][j] * gy[i][j], 0.5)
            theta = math.atan(gy[i][j] / gx[i][j]) * 180 / 3.1415926
            if theta >= 0 and theta < 45:
                dirr[i][j] = 2
            elif theta >= 45 and theta < 90:
                dirr[i][j] = 3
            elif theta >= 90 and theta < 135:
                dirr[i][j] = 0
            else:
                dirr[i][j] = 1
    for i in range(1, height - 1, 1):  # 非极大值抑制,双阈值监测
        for j in range(1, width - 1, 1):
            NW = gm[i - 1][j - 1]
            N = gm[i - 1][j]
            NE = gm[i - 1][j + 1]
            W = gm[i][j - 1]
            E = gm[i][j + 1]
            SW = gm[i + 1][j - 1]
            S = gm[i + 1][j]
            SE = gm[i + 1][j + 1]
            if dirr[i][j] == 0:
                d = abs(gy[i][j] / gx[i][j])
                gp1 = (1 - d) * E + d * NE
                gp2 = (1 - d) * W + d * SW
            elif dirr[i][j] == 1:
                d = abs(gx[i][j] / gy[i][j])
                gp1 = (1 - d) * N + d * NE
                gp2 = (1 - d) * S + d * SW
            elif dirr[i][j] == 2:
                d = abs(gx[i][j] / gy[i][j])
                gp1 = (1 - d) * N + d * NW
                gp2 = (1 - d) * S + d * SE
            elif dirr[i][j] == 3:
                d = abs(gy[i][j] / gx[i][j])
                gp1 = (1 - d) * W + d * NW
                gp2 = (1 - d) * E + d * SE
            if gm[i][j] >= gp1 and gm[i][j] >= gp2:
                if gm[i][j] >= highhold:
                    highorlow[i][j] = 2
                    rm[i][j] = 1
                elif gm[i][j] >= lowhold:
                    highorlow[i][j] = 1
                else:
                    highorlow[i][j] = 0
                    rm[i][j] = 0
            else:
                highorlow[i][j] = 0
                rm[i][j] = 0
    for i in range(1, height - 1, 1):  # 抑制孤立低阈值点
        for j in range(1, width - 1, 1):
            if highorlow[i][j] == 1 and (
                    highorlow[i - 1][j - 1] == 2 or highorlow[i - 1][j] == 2 or highorlow[i - 1][j + 1] == 2 or
                    highorlow[i][j - 1] == 2 or highorlow[i][j + 1] == 2 or highorlow[i + 1][j - 1] == 2 or
                    highorlow[i + 1][j] == 2 or highorlow[i + 1][j + 1] == 2):
                # highorlow[i][j]=2
                rm[i][j] = 1
    # img=Image.fromarray(rm)#矩阵化为图片
    # img.show()
    # new = np.concatenate((im, image), axis=1)
    # cv2.imwrite('combined.jpg', new)

    # 正方形法判定是否有马赛克
    value = 20
    lowvalue = 16
    imgnumber = [0 for i in range(value)]
    for i in range(1, height - 1, 1):  # 性价比高的8点判定法
        for j in range(1, width - 1, 1):
            for k in range(lowvalue, value):
                count = 0
                if i + k - 1 >= height or j + k - 1 >= width:
                    continue
                if rm[i][j] != 0:
                    count += 1  # 4个顶点
                if rm[i + k - 1][j] != 0:
                    count += 1
                if rm[i][j + k - 1] != 0:
                    count += 1
                if rm[i + k - 1][j + k - 1] != 0:
                    count += 1
                e = (k - 1) // 2
                if rm[i + e][j] != 0:
                    count += 1
                if rm[i][j + e] != 0:
                    count += 1
                if rm[i + e][j + k - 1] != 0:
                    count += 1
                if rm[i + k - 1][j + e] != 0:
                    count += 1
                if count >= 6:
                    imgnumber[k] += 1
    for i in range(lowvalue, value):
        file.write("length:{}  number:{}".format(i, imgnumber[i]) + "\n")


def get_all_mosaic(dir_url):
    start_time = time.time()
    num_lists = []
    list = os.listdir(dir_url)
    for i in list:
        num = int(i.split(".")[0])
        num_lists.append(num)
    num_lists = sort(num_lists)
    for j in num_lists:
        print(j)
        url = dir_url + str(j) + ".jpg"
        test_mosaic(url)
    end_time = time.time()
    print(f"get_all_mosaic time consumption: {str(end_time - start_time)} seconds")


if __name__ == '__main__':
    url = "Desktop/ceshi/"
    get_all_mosaic(url)
    # smaller_cmd = '/opt/homebrew/bin/ffmpeg -i ' + str(url) + ' -vf scale=320:-1 tmp.png'
    # # smaller_cmd = '/opt/homebrew/bin/ffmpeg -i ' + str(url) + ' -vf "scale=iw/6:ih/6" tmp.png'
    # os.popen(smaller_cmd).read()
    # test("tmp.png")

【代码2】自定义逻辑

import cv2
import os
import numpy as np

# 学习link:本文链接:https://blog.csdn.net/LPYchengxuyuan/article/details/122003702
#定义形状检测函数
def ShapeDetection(img):
    msk_num = 0
    img_area = []
    Square_area = []
    triangle_area = []
    Rectangle_area = []
    Circle_area = []
    Square_x_y = []
    Square_w_h = []
    imgGray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)  # 转灰度图
    imgBlur = cv2.GaussianBlur(imgGray, (5, 5), 1)  # 高斯模糊
    imgCanny = cv2.Canny(imgBlur, 60, 60)  # Canny算子边缘检测
    cv2.imwrite("shape_Detection.png", imgContour)
    triangle_num = 0
    Square_num = 0
    Rectangle_num = 0
    Circle_num = 0
    not_Square_num = 0

    area_5 = []
    area_6 = []
    area_7 = []
    area_8 = []
    area_9 = []
    area_10 = []
    area_11 = []
    area_12 = []
    area_13 = []

    contours,hierarchy = cv2.findContours(imgCanny,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_NONE)  #寻找轮廓点
    for obj in contours:
        area = cv2.contourArea(obj)  #计算轮廓内区域的面积
        cv2.drawContours(imgContour, obj, -1, (255, 0, 0), 4)  #绘制轮廓线
        perimeter = cv2.arcLength(obj,True)  #计算轮廓周长
        approx = cv2.approxPolyDP(obj,0.02*perimeter,True)  #获取轮廓角点坐标
        CornerNum = len(approx)   #轮廓角点的数量
        x, y, w, h = cv2.boundingRect(approx)  #获取坐标值和宽度、高度
        # 添加正方形的判断
        if CornerNum == 3:
            objType = "triangle"
            not_Square_num += 1
            triangle_area.append(area)
        elif CornerNum == 4:
            if w == h:
                objType = "Square"
                Square_num += 1
                Square_area.append(area)
                Square_x_y.append([x,y])
                Square_w_h.append(w)
                cv2.rectangle(imgContour, (x, y), (x + w, y + h), (0, 0, 255), 2)  # 绘制边界框
                cv2.putText(imgContour, objType, (x + (w // 2), y + (h // 2)), cv2.FONT_HERSHEY_COMPLEX, 0.6, (0, 0, 0),1)  # 绘制文字
            else:
                objType = "Rectangle"
                not_Square_num += 1
                # img_area.append(area)
                Rectangle_area.append(area)
        elif CornerNum == 5:
            area_5.append(area)
        elif CornerNum == 6:
            area_6.append(area)
        elif CornerNum == 7:
            area_7.append(area)
        elif CornerNum == 8:
            area_8.append(area)
        elif CornerNum == 9:
            area_9.append(area)
        elif CornerNum == 10:
            area_10.append(area)
        elif CornerNum == 11:
            area_11.append(area)
        elif CornerNum == 12:
            area_12.append(area)
        elif CornerNum == 13:
            area_13.append(area)
        else:
            objType = "N"
            not_Square_num += 1
            img_area.append(area)

    print(triangle_num,Square_num,Rectangle_num,Circle_num,not_Square_num)
    print(sum(triangle_area),sum(Square_area),sum(Rectangle_area),sum(area_5),sum(area_6),sum(area_7),sum(area_8),sum(area_9),sum(area_10),sum(area_11),sum(area_12),sum(area_13),sum(img_area))

    # print(Square_x_y)
    # print(Square_w_h)
    rm_cmd = "rm -rf ./tmp/*.png ./tmp/*.ts"
    os.popen(rm_cmd).read()
    # cv2.imwrite("./tmp/Original_img.png", img)
    # cv2.imwrite("./tmp/imgGray.png", imgGray)
    # cv2.imwrite("./tmp/imgBlur.png", imgBlur)
    cv2.imwrite("./tmp/imgCanny.png", imgCanny)
    cv2.imwrite("./tmp/shape_Detection.png", imgContour)

    if test_msk_1(Square_num,not_Square_num) is True and test_msk_2(Square_num,Square_w_h) and True or test_msk_3(Square_area) is True:
        msk_num += 1
        print("这张图片马赛克")
    else:
        print("这张图片正常")
    print("马赛克张数:" + str(msk_num))

# 添加马赛克的判断
"""
1、正方形的个数占所有形状的2/3
2、统计相同长度的正方形个数,前三名正方形占所有正方形个数的1/3
3、统计相同长度的正方形个数,前三名正方形面积占所有正方形面积的1/3
"""

def test_msk_1(Square_num,not_Square_num):
    msk_num = 0
    if not_Square_num == 0:
        return
    if Square_num / not_Square_num >= 2/3:
        print("1正方形的个数/所有形状:" + Square_num / not_Square_num)
        msk_num += 1
    if msk_num > 0:
        return True
    else:
        return False


def test_msk_2(Square_num,Square_w_h):
    msk_num = 0
    # 求正方形不同长度的个数字典
    Square_num_info = {}
    for i in Square_w_h:
        if i not in Square_num_info:
            Square_num_info[i] = 1
        else:
            Square_num_info[i] += 1
    Square_num_info_value = list(Square_num_info.values())
    # 求个数前三的长度
    if Square_num_info_value == None or len(Square_num_info_value) == 0:
        print("参数不合法!")
        return True
    elif len(Square_num_info_value) == 1:
        print("正方形" + str(Square_num_info_value[0]))
        return True
    elif len(Square_num_info_value) == 2:
        print("正方形" + str(Square_num_info_value[0]) + str(Square_num_info_value[1]))
        return True
    r1 = r2 = r3 = -2 ** 31
    i = 0
    while i < len(Square_num_info_value):
        if Square_num_info_value[i] > r1:
            r3 = r2
            r2 = r1
            r1 = Square_num_info_value[i]
        # elif C[i] > r2 and C[i] != r1:
        elif Square_num_info_value[i] > r2:
            r3 = r2
            r2 = Square_num_info_value[i]
        # elif C[i] > r3 and C[i] != r2:
        elif Square_num_info_value[i] > r3:
            r3 = Square_num_info_value[i]
        i += 1
    top3_Square_num = r1 + r2 + r3
    if top3_Square_num / Square_num >= 1/3:
        print(top3_Square_num,Square_num)
        print("2前三正方形个数/总正方形个数的:" + str(top3_Square_num / Square_num))
        msk_num += 1
    if msk_num > 0:
        return True
    else:
        return False


def test_msk_3(Square_area):
    msk_num = 0
    all_area = sum(Square_area)
    # 求正方形不同长度的面积字典
    Square_num_info = {}
    for i in Square_area:
        if i not in Square_num_info:
            Square_num_info[i] = 1
        else:
            Square_num_info[i] += 1
    Square_num_info_value = list(Square_num_info.values())
    print(Square_num_info)
    print(Square_num_info_value)
    # 求个数前三的面积
    if Square_num_info_value == None or len(Square_num_info_value) == 0:
        print("参数不合法!")
        return True
    elif len(Square_num_info_value) == 1:
        top3_Square_num = Square_num_info_value[0]
        print("Square_num_info_value:" + str(top3_Square_num))
        return True
    elif len(Square_num_info_value) == 2:
        top3_Square_num = Square_num_info_value[0] + Square_num_info_value[1]
        print("Square_num_info_value:" + str(top3_Square_num))
        return True
    r1 = r2 = r3 = -2 ** 31
    i = 0
    while i < len(Square_num_info_value):
        if Square_num_info_value[i] > r1:
            r3 = r2
            r2 = r1
            r1 = Square_num_info_value[i]
        elif Square_num_info_value[i] > r2:
            r3 = r2
            r2 = Square_num_info_value[i]
        elif Square_num_info_value[i] > r3:
            r3 = Square_num_info_value[i]
        i += 1
    top3_Square_num = []
    top3_Square_num.append(r1)
    top3_Square_num.append(r2)
    top3_Square_num.append(r3)
    top1 = [k for k, v in Square_num_info.items() if v == r1]
    top2 = [k for k, v in Square_num_info.items() if v == r2]
    top3 = [k for k, v in Square_num_info.items() if v == r3]
    top3_Square_length = top1 + top2 + top3
    top3_Square_length = list(dict.fromkeys(top3_Square_length))
    top3_Square_area = 0
    for i in range(0,3):
        print(top3_Square_length[i],top3_Square_num[i])
        top3_Square_area += top3_Square_length[i] * top3_Square_num[i]
    print(top3_Square_area,all_area)
    if top3_Square_area / all_area >= 2/3:
        print("3前三正方形面积/总正方形:" + str(top3_Square_area / all_area))
        msk_num += 1
    if msk_num > 0:
        return True
    else:
        return False


if __name__ == '__main__':
    path = 'Desktop/huaping/1.png'
    img = cv2.imread(path)
    imgContour = img.copy()
    ShapeDetection(img)
    # for i in range(1,11):
    #     path = 'Desktop/ceshi/' + str(i) + '.jpg'
    #     img = cv2.imread(path)
    #     imgContour = img.copy()
    #     ShapeDetection(img)

    # for i in range(50):
    #     path = 'Desktop/ceshi2/' + str(i) + '.jpg'
    #     img = cv2.imread(path)
    #     imgContour = img.copy()
    #     ShapeDetection(img)
    #     i += 1
    # print(i)

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

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

相关文章

buuctf-web-[BJDCTF2020]Easy MD51

打开环境一个简单的页面查看源代码一个get传参&#xff0c;随便输入试试看输入1,1",1,均无反应&#xff0c;每次遇到这种有输入框的都以为是sql注入&#xff0c;但是题目为md5标头里面看到提示select * from admin where passwordmd5($pass,true)搜索相关漏洞&#xff0c;…

gost 常用tunnel配置示例(隧道模式)

gost是用golang语言实现的一个安全隧道。地址位于&#xff1a;https://github.com/ginuerzh/gost是一个不可多得的隧道工具。至于什么是隧道&#xff1f; 就是可以通过这个工具传输一些其他协议的数据。就像这个样子。隧道有什么用呢&#xff1f;可以起到一些加速的作用或者流量…

Array.prototype.from()

Array.from() 用于将类数组对象或可迭代对象转化为一个新的浅拷贝数组实例。 let arr Array.from({length:3},(_,i)>({id:item-${i1}}))console.log(arr)Array.from()转换数组 // Array.from 转换成数组let arr2 Array.from(chixinAwen)console.log(arr2) 示例&#xff1a…

如何免安装使用 Python?推荐 17 个在线的 Python 解释器

安装 Python 很容易&#xff0c;但或许你正在用智能手机/平板电脑&#xff0c;在用不允许安装软件的电脑&#xff0c;或者因为其它原因无法安装 Python。那么&#xff0c;如何通过免安装的方式使用 Python 呢&#xff1f; 本文将介绍 17 个免费的 Python 解释器和交互式 Shell…

百里挑一,4款免费又实用的软件,用一次就爱上

好看的皮囊千篇一律&#xff0c;实用的软件百里挑一&#xff0c;下面几款软件都是笔者收集多年所得&#xff0c;实用且免费。 1、坚果云 这是一款颠覆许多人认知的网盘工具&#xff0c;免费使用无广告&#xff0c;不限速的优点就比某度网盘强百倍&#xff0c;支持任何设备&…

AOP案例:测量业务层接口万次执行时间

测量业务层接口万次执行时间1. 准备1.1 service层&#xff1a;1.2 dao层&#xff1a;1.3 SpringConfig配置类&#xff1a;2. AOP2.1 通知类2.2 测试类&#xff1a;3. 问题及改进1. 准备 需求&#xff1a;任意业务层接口执行均可显示执行的时长&#xff1b; 切入点配置&#x…

(day9) 自学Java——常用API

AIP就是Java已经写好的各种功能的java类 目录 1.Math 2.System 3.Runtime 4.Object 5.对象工具类Objects 6.BIgInteger 7.BigDecima 8.正则表达式 (1)爬虫 (2)带条件爬取&#xff0c;贪婪爬取和识别正则的两个方法 (3)捕获分组和非捕获分组 9.JDK7以前时间相关类 …

一起自学SLAM算法:12.3 autoware导航系统

连载文章&#xff0c;长期更新&#xff0c;欢迎关注&#xff1a; 上面介绍的ros-navigation和riskrrt导航系统主要都是用于机器人的低速导航&#xff0c;并且大多基于2D地图。而autoware导航系统主要用于无人驾驶汽车的高速导航&#xff0c;并且基于3D地图。除了所导航速度高一…

软件工程(一)——软件开发模型和方法

目录 &#xff08;一&#xff09;软件开发方法 &#xff08;二&#xff09;瀑布模型 &#xff08;三&#xff09;原型模型 &#xff08;四&#xff09;螺旋模型与增量模型 &#xff08;五&#xff09;V模型、喷泉模型、RAD模型 (六) 统一过程&#xff08;RUP&#xff09; …

idea 中 connot run program “svn“ 系统找不到文件

idea 中 connot run program “svn“ 系统找不到文件1. idea中svn的问题1.1 idea connot run program "svn"1.1.1 解决办法-重装svn1.2 idea中check out灰色不可用1.2.1 解决办法—装插件1. idea中svn的问题 1.1 idea connot run program “svn” 如图&#xff1a;…

2023年机床工具行业研究报告

第一章 行业概况 生产和销售机床工具的行业。机床是指制造机器的机器&#xff0c;亦称工作母机或工具机&#xff0c;习惯上简称机床。一般分为金属切削机床、锻压机床和木工机床等。现代机械制造中加工机械零件的方法很多&#xff1a;除切削加工外&#xff0c;还有铸造、锻造、…

【ES实战】索引生命周期管理(一)

索引生命周期管理IL&#xff2d;&#xff08;index lifecycle management&#xff09; 文章目录索引生命周期管理IL&#xff2d;&#xff08;index lifecycle management&#xff09;概述版本矩阵主要概念索引生命周期阶段的过渡阶段的执行生命周期中的操作生命周期策略索引翻滚…

AzureRT:一款能够实现各种Azure红队技战术的PowerShell模块

关于AzureRT AzureRT是一款能够实现各种Azure红队技战术的PowerShell模块&#xff0c;在AzureRT的帮助下&#xff0c;广大研究人员可以从攻击者的角度来与Azure和Azure AD进行交互&#xff0c;以此来测试目标环境的安全性。 AzureRT可以帮助广大研究人员测试和处理基于访问令…

【工具】操作PDF推荐的java依赖

Apache PDFBox |一个 Java PDF 库 <dependency><groupId>org.apache.pdfbox</groupId><artifactId>pdfbox-app</artifactId><version>2.0.27</version></dependency> Apache PDFBox - A Java PDF Library Apache PDFBox 库…

超详解线段树(浅显易懂)

一&#xff0c;什么是线段树&#xff1f;线段树是怎样的树形结构?线段树是一种二叉搜索树&#xff0c;而二叉搜索树&#xff0c;首先满足二叉树&#xff0c;即每个结点最多有两颗子树&#xff0c;并且是一颗搜索树&#xff0c;我们要知道&#xff0c;线段树的每个结点都存储了…

用于在过程工业中参数化配置现场设备的移动式解决方案

EndressHauser提供了一个组合套件&#xff08;包含Field Xpert和Softing的mobiLink通信工具&#xff09;&#xff0c;可用于参数化配置和现场调试。 &#xff08;将Softing的mobiLink通信工具与EndressHauser的Field Xpert SMT70或SMT77平板电脑相结合使用&#xff0c;可为用户…

再见 Matplotlib 和 Seaborn ,Python 画图建议用这个

本文主要介绍 Python 中用来替代 Matplotlib 和 Seaborn 的可视化工具 plotly&#xff0c;并结合实例讲解了 plotly 的优点和用法&#xff0c;满足了可视化绘图的交互需求。 数据可视化是人脑有效理解各种信息的最舒适、最直观的方式。对于需要处理数据的人来说&#xff0c;能…

谈思生物直播课|辛格迪副总裁“细胞治疗数字化解决方案”

近年来&#xff0c;细胞基因治疗在全球范围内得到了快速的发展。因为细胞基因治疗药物的特殊性&#xff08;从人体中采得活细胞&#xff0c;经过特别的处理技术后再输入人体&#xff09;&#xff0c;其安全性也被监管机构和药企高度关注&#xff1b;同时&#xff0c;也由于其制…

Laravel笔记-使用composer搭建Laravel环境(开发工具phpStorm)

以前写过一个&#xff0c;但没这个composer直接搭建的方便。在此记录下。 使用国内的 Composer 加速镜像 composer config -g repo.packagist composer https://mirrors.aliyun.com/composer/ 新建一个名为MyRestfulTest的项目&#xff1a; composer create-project larave…

测试go test

目录go test工具单元测试测试代码go test -run跳过某些测试用例子测试表格驱动测试并行测试报告方法测试覆盖率基准测试demo性能比较函数计时方法并行测试TestMainSetup与Teardownhttptest简单的 Web 应用测试Go 语言从开发初期就注意了测试用例的编写。特别是静态语言&#xf…