OpenCV数字图像处理——检测出图像中的几何形状并测量出边长、直径、内角

一、简介

在传统的自动化生产尺寸测量中,常用的方法是利用卡尺或千分尺对被测工件的某个参数进行多次测量,并取这些测量值的平均值。然而,这些传统的检测设备或手动测量方法存在着一些问题:测量精度不高、测量速度缓慢,以及测量数据无法及时处理等。这些局限性导致无法满足大规模自动化生产的需求。

相比之下,基于机器视觉技术的尺寸测量方法具有以下优点:

  1. 成本低: 机器视觉设备相对传统设备成本较低,而且在某些情况下,可以使用普通的摄像头。
  2. 精度高: 机器视觉系统能够提供高精度的测量结果,可达到微米级别的精度。
  3. 非接触性: 不需要物理接触被测量物体,避免了对物体的损伤或变形。
  4. 实时性: 可以实时获取测量结果,提高生产效率并及时发现问题。
  5. 灵活性: 机器视觉系统可适应不同形状和尺寸的工件,具有较强的适应性和灵活性。

在自动化制造行业中,机器视觉技术广泛应用于工件尺寸测量。通过机器视觉系统,可以测量工件的长度、直径、角度、曲率等多个尺寸参数,甚至可以检测产品的相关区域的基本几何特征。这种技术不仅能够实时获取产品的尺寸参数,还能够进行在线实时判定和分拣,对自动化生产起到重要作用。

基于机器视觉的应用已涵盖下面几个领域:

1. 医学影像学
  • 测量肿瘤或器官尺寸: 利用医学影像处理技术测量肿瘤或器官在医学图像中的尺寸。
2. 工程和制造
  • 检测零件尺寸: 在制造业中检测工件的尺寸和缺陷,确保产品质量和精度。
  • 装配和定位: 使用图像处理技术进行装配和定位,确保零件正确放置和对齐。
3. 地理信息系统(GIS)和遥感
  • 测量地表特征: 在GIS中,使用遥感图像测量地表特征的面积和分布。
  • 地形测量: 利用数字高程模型(DEM)和遥感技术测量地形高度和地势。
4. 农业和环境科学
  • 植被分析: 对农作物生长和土地利用进行分析和评估。
  • 土地利用测量: 使用图像处理技术测量农田、森林覆盖率和土地利用类型。
5. 机器视觉和自动化
  • 产品检测和测量: 在自动化制造中使用图像处理技术检测和测量产品尺寸和位置。
  • 导航和定位: 在自动驾驶和机器人导航中使用图像来感知环境和进行定位。

在本文中,不涉及对相机与镜头如何选型,相机镜头角度(水平视角、垂直视角、对角线)误差、相机安装高度、检测视野、测量精度、光源和滤光片选择等这些关于硬件设备知识。如果想深入地探究的讨论这些硬件主题,可以私信博主。

二、测量流程与原理

1、项目流程

先看整体项目实现的流程,整个流程最重要应该是目标分割这块,如果不分割好,到后面做什么处理都没有什么意义,目标可以使用传统图像处理来分割,也可以基于深度学习的语义分割来实现。
在这里插入图片描述
基于深度学习和传统图像处理方法之间区别:

  1. 特征提取方法:
  • 传统图像处理: 传统方法主要依赖于手工设计的特征提取器,如边缘检测器、滤波器等。这些方法通常需要对数字处理有专业知识才能选择和设计适当的特征提取方式。

  • 深度学习: 深度学习模型能够自动地从数据中学习到最优的特征表示。卷积神经网络(CNN)等深度学习架构可以学习到图像中的抽象特征,无需手动设计特征提取器。

  1. 数据需求量:
  • 传统图像处理: 传统方法对于特征的提取和处理通常需要有关专门领域的预定义知识,有时需要大量手动标注的数据。

  • 深度学习: 深度学习方法对于大规模数据集的需求更为显著,尤其是需要大量标记的数据以训练复杂的深度神经网络。

  1. 通用性和灵活性:
  • 传统图像处理: 传统方法通常针对特定问题设计,因此在其他问题上可能不具备通用性,场景泛化能力差。

  • 深度学习: 深度学习模型可以更好地泛化到未见过的数据,并在不同领域中展现出更强的通用性和灵活性。

  1. 调参和复杂性:
  • 传统图像处理: 传统方法通常需要手动调整参数和特征提取器的设计,这需要代码人员具有专业图像处理知识和经验。

  • 深度学习: 深度学习模型通常有更多的超参数需要调整,并且相对更复杂。因此,训练深度学习模型可能需要更多的计算资源和时间。

  1. 适用范围:
  • 传统图像处理: 传统方法在某些特定任务上仍然具有优势,例如简单的图像滤波、边缘检测等领域。

  • 深度学习: 深度学习在许多领域取得了重大突破,例如图像分类、物体检测、分割、生成对抗网络等,使得在复杂问题上取得了更好的表现。

2.长度测量

图像里面的线段测量,首先要理解“每度量比的像素”(pixels per metric ratio),它类似于比例尺,通过已知图像上一个对象的尺寸和该对象在图像中所占像素的数量,可以得到一个比例关系,从而可以将其他物体的像素转换为实际度量单位(如厘米、毫米等)。

关键属性包括:

  1. 已知长度:需要知道图像中一个物体的实际长度,通常是以某种可测量的单位(例如毫米、英寸等)来表示。
  2. 像素数量:该已知长度物体在图像中所占据的像素数。这可以通过在图像中测量该物体的像素宽度或高度来获取。

有了这两个属性,就可以计算出每个度量单位所对应的像素数。这个比例关系将图像中的像素转换为实际的度量单位,从而可以测量其他物体的大小或长度。
在这里插入图片描述
“Known length in pixels” 是图像中已知长度参考物体所占据的像素数,“Known length in metrics” 是已知长度参考物体的实际尺寸。

3、角度测量

在角度测量中,首先要明确一个定理,几何形状和其中的角度大小是与图像的比例无关的。在几何学中,角度的大小是由几何形状的内部构造和相对位置所确定的,而不受图像的放大或缩小影响。
当图像被放大或缩小时,图像中的对象尺寸和比例会改变,但这并不影响对象之间的相对位置和角度的大小。换句话说,图像的尺寸变化并不会改变对象内部的角度测量。
例如,如果一个图像中有一个特定角度的三角形,在放大或缩小图像的过程中,三角形内部的角度大小将保持不变。无论图像是多大还是多小,角度大小都取决于三角形的内部构造和边的相对位置,而不是取决于图像的尺寸或比例。由于角度在图像尺寸的变化过程中保持不变,图像中的角度测量就不用参照另外的参数。

三、代码实现

为了方便理解,这里实现所用的代码都是基于传统数字图像处理,实现依赖库是OpenCV,实现语言是Python,如果要应用到实际生产环境当中,这套方法并不是最可靠的,最好是选择使用流程图里面提到的基于深度学习的方法。

代码的实现是识别与测量放在一张A4纸上的所有几何图形的边长,内角值,直径,圆心。

1.数据处理

首先使用手机拍几张A4纸,纸上放着想要测量的几何图形目标,如下图:
在这里插入图片描述
使用代码把图像中的A4区域切出来:

from pyimagesearch import transform
from pyimagesearch import imutils
from matplotlib.patches import Polygon
import polygon_interacter as poly_i
import numpy as np
import matplotlib.pyplot as plt
import itertools
import math
import cv2
from pylsd.lsd import lsd


from scipy.spatial import distance as dist


def midpoint(ptA, ptB):
	return ((ptA[0] + ptB[0]) * 0.5, (ptA[1] + ptB[1]) * 0.5)

class DocScanner(object):
    """An image scanner"""

    def __init__(self, interactive=False, MIN_QUAD_AREA_RATIO=0.25, MAX_QUAD_ANGLE_RANGE=40):

        self.interactive = interactive
        self.MIN_QUAD_AREA_RATIO = MIN_QUAD_AREA_RATIO
        self.MAX_QUAD_ANGLE_RANGE = MAX_QUAD_ANGLE_RANGE        

    def filter_corners(self, corners, min_dist=20):
        """Filters corners that are within min_dist of others"""
        def predicate(representatives, corner):
            return all(dist.euclidean(representative, corner) >= min_dist
                       for representative in representatives)

        filtered_corners = []
        for c in corners:
            if predicate(filtered_corners, c):
                filtered_corners.append(c)
        return filtered_corners

    def angle_between_vectors_degrees(self, u, v):
        """Returns the angle between two vectors in degrees"""
        return np.degrees(
            math.acos(np.dot(u, v) / (np.linalg.norm(u) * np.linalg.norm(v))))

    def get_angle(self, p1, p2, p3):

        a = np.radians(np.array(p1))
        b = np.radians(np.array(p2))
        c = np.radians(np.array(p3))

        avec = a - b
        cvec = c - b

        return self.angle_between_vectors_degrees(avec, cvec)

    def angle_range(self, quad):

        tl, tr, br, bl = quad
        ura = self.get_angle(tl[0], tr[0], br[0])
        ula = self.get_angle(bl[0], tl[0], tr[0])
        lra = self.get_angle(tr[0], br[0], bl[0])
        lla = self.get_angle(br[0], bl[0], tl[0])

        angles = [ura, ula, lra, lla]
        return np.ptp(angles)          

    def get_corners(self, img):

        lines = lsd(img)


        corners = []
        if lines is not None:
            # separate out the horizontal and vertical lines, and draw them back onto separate canvases
            lines = lines.squeeze().astype(np.int32).tolist()
            horizontal_lines_canvas = np.zeros(img.shape, dtype=np.uint8)
            vertical_lines_canvas = np.zeros(img.shape, dtype=np.uint8)
            for line in lines:
                x1, y1, x2, y2, _ = line
                if abs(x2 - x1) > abs(y2 - y1):
                    (x1, y1), (x2, y2) = sorted(((x1, y1), (x2, y2)), key=lambda pt: pt[0])
                    cv2.line(horizontal_lines_canvas, (max(x1 - 5, 0), y1), (min(x2 + 5, img.shape[1] - 1), y2), 255, 2)
                else:
                    (x1, y1), (x2, y2) = sorted(((x1, y1), (x2, y2)), key=lambda pt: pt[1])
                    cv2.line(vertical_lines_canvas, (x1, max(y1 - 5, 0)), (x2, min(y2 + 5, img.shape[0] - 1)), 255, 2)

            lines = []

            # find the horizontal lines (connected-components -> bounding boxes -> final lines)
            (contours, hierarchy) = cv2.findContours(horizontal_lines_canvas, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
            contours = sorted(contours, key=lambda c: cv2.arcLength(c, True), reverse=True)[:2]
            horizontal_lines_canvas = np.zeros(img.shape, dtype=np.uint8)
            for contour in contours:
                contour = contour.reshape((contour.shape[0], contour.shape[2]))
                min_x = np.amin(contour[:, 0], axis=0) + 2
                max_x = np.amax(contour[:, 0], axis=0) - 2
                left_y = int(np.average(contour[contour[:, 0] == min_x][:, 1]))
                right_y = int(np.average(contour[contour[:, 0] == max_x][:, 1]))
                lines.append((min_x, left_y, max_x, right_y))
                cv2.line(horizontal_lines_canvas, (min_x, left_y), (max_x, right_y), 1, 1)
                corners.append((min_x, left_y))
                corners.append((max_x, right_y))

            # find the vertical lines (connected-components -> bounding boxes -> final lines)
            (contours, hierarchy) = cv2.findContours(vertical_lines_canvas, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
            contours = sorted(contours, key=lambda c: cv2.arcLength(c, True), reverse=True)[:2]
            vertical_lines_canvas = np.zeros(img.shape, dtype=np.uint8)
            for contour in contours:
                contour = contour.reshape((contour.shape[0], contour.shape[2]))
                min_y = np.amin(contour[:, 1], axis=0) + 2
                max_y = np.amax(contour[:, 1], axis=0) - 2
                top_x = int(np.average(contour[contour[:, 1] == min_y][:, 0]))
                bottom_x = int(np.average(contour[contour[:, 1] == max_y][:, 0]))
                lines.append((top_x, min_y, bottom_x, max_y))
                cv2.line(vertical_lines_canvas, (top_x, min_y), (bottom_x, max_y), 1, 1)
                corners.append((top_x, min_y))
                corners.append((bottom_x, max_y))

            # find the corners
            corners_y, corners_x = np.where(horizontal_lines_canvas + vertical_lines_canvas == 2)
            corners += zip(corners_x, corners_y)

        # remove corners in close proximity
        corners = self.filter_corners(corners)
        return corners

    def is_valid_contour(self, cnt, IM_WIDTH, IM_HEIGHT):
        """Returns True if the contour satisfies all requirements set at instantitation"""

        return (len(cnt) == 4 and cv2.contourArea(cnt) > IM_WIDTH * IM_HEIGHT * self.MIN_QUAD_AREA_RATIO 
            and self.angle_range(cnt) < self.MAX_QUAD_ANGLE_RANGE)


    def get_contour(self, rescaled_image):

        # these constants are carefully chosen
        MORPH = 9
        CANNY = 84
        HOUGH = 25

        IM_HEIGHT, IM_WIDTH, _ = rescaled_image.shape

        # convert the image to grayscale and blur it slightly
        gray = cv2.cvtColor(rescaled_image, cv2.COLOR_BGR2GRAY)
        gray = cv2.GaussianBlur(gray, (7,7), 0)

        # dilate helps to remove potential holes between edge segments
        kernel = cv2.getStructuringElement(cv2.MORPH_RECT,(MORPH,MORPH))
        dilated = cv2.morphologyEx(gray, cv2.MORPH_CLOSE, kernel)

        # find edges and mark them in the output map using the Canny algorithm
        edged = cv2.Canny(dilated, 0, CANNY)
        test_corners = self.get_corners(edged)

        approx_contours = []

        if len(test_corners) >= 4:
            quads = []

            for quad in itertools.combinations(test_corners, 4):
                points = np.array(quad)
                points = transform.order_points(points)
                points = np.array([[p] for p in points], dtype = "int32")
                quads.append(points)

            # get top five quadrilaterals by area
            quads = sorted(quads, key=cv2.contourArea, reverse=True)[:5]
            # sort candidate quadrilaterals by their angle range, which helps remove outliers
            quads = sorted(quads, key=self.angle_range)

            approx = quads[0]
            if self.is_valid_contour(approx, IM_WIDTH, IM_HEIGHT):
                approx_contours.append(approx)

        # also attempt to find contours directly from the edged image, which occasionally 
        # produces better results
        (cnts, hierarchy) = cv2.findContours(edged.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
        cnts = sorted(cnts, key=cv2.contourArea, reverse=True)[:5]

        # loop over the contours
        for c in cnts:
            # approximate the contour
            approx = cv2.approxPolyDP(c, 80, True)
            if self.is_valid_contour(approx, IM_WIDTH, IM_HEIGHT):
                approx_contours.append(approx)
                break

        # If we did not find any valid contours, just use the whole image
        if not approx_contours:
            TOP_RIGHT = (IM_WIDTH, 0)
            BOTTOM_RIGHT = (IM_WIDTH, IM_HEIGHT)
            BOTTOM_LEFT = (0, IM_HEIGHT)
            TOP_LEFT = (0, 0)
            screenCnt = np.array([[TOP_RIGHT], [BOTTOM_RIGHT], [BOTTOM_LEFT], [TOP_LEFT]])

        else:
            screenCnt = max(approx_contours, key=cv2.contourArea)
            
        return screenCnt.reshape(4, 2)

    def interactive_get_contour(self, screenCnt, rescaled_image):
        poly = Polygon(screenCnt, animated=True, fill=False, color="yellow", linewidth=5)
        fig, ax = plt.subplots()
        ax.add_patch(poly)
        ax.set_title(('Drag the corners of the box to the corners of the document. \n'
            'Close the window when finished.'))
        p = poly_i.PolygonInteractor(ax, poly)
        plt.imshow(rescaled_image)
        plt.show()

        new_points = p.get_poly_points()[:4]
        new_points = np.array([[p] for p in new_points], dtype = "int32")
        return new_points.reshape(4, 2)

    def scan(self, cv_src):

        RESCALED_HEIGHT = 500.0

        ratio = cv_src.shape[0] / RESCALED_HEIGHT
        orig = cv_src.copy()
        rescaled_image = imutils.resize(cv_src, height = int(RESCALED_HEIGHT))

        # get the contour of the document
        screenCnt = self.get_contour(rescaled_image)

        if self.interactive:
            screenCnt = self.interactive_get_contour(screenCnt, rescaled_image)

        # apply the perspective transformation
        warped = transform.four_point_transform(orig, screenCnt * ratio)

        return warped


if __name__ == "__main__":
    interactive_mode = 'store_true'
    scanner = DocScanner(interactive_mode)
    cv_src = cv2.imread('1.JPG')
    cv_dst = scanner.scan(cv_src)

    cv2.namedWindow('dst',0)
    cv2.imshow('dst',cv_dst)
    cv2.waitKey()

在这里插入图片描述

2.分割出图像里面的几何图形

	cv_src = cv_or.copy()

    dis_ref = dist.euclidean((start_point[0], start_point[1]), (end_point[0], end_point[1]))

    blurred_image = cv2.GaussianBlur(cv_src, (11, 11), 0)
    cv_gray = cv2.cvtColor(blurred_image, cv2.COLOR_BGR2GRAY)

    _, threshold = cv2.threshold(cv_gray, 100, 255, cv2.THRESH_BINARY)
    # threshold = cv2.adaptiveThreshold(cv_gray, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 25,1)

    # cv2.namedWindow('th',0)
    # cv2.imshow('th',threshold)
    # cv2.waitKey()

    kernel = np.ones((13, 13), np.uint8)
    # closed_image = cv2.morphologyEx(threshold, cv2.MORPH_CLOSE, kernel)
    opened_image = cv2.morphologyEx(threshold, cv2.MORPH_OPEN, kernel)

    erosion = cv2.erode(~opened_image, (3,3), iterations=1)

    # cv2.imshow('op',erosion)

在这里插入图片描述

3.识别几何图形

import cv2
import numpy as np

# 读取图像并转换为灰度图
image = cv2.imread('shapes.jpg')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

# 阈值化图像
_, thresh = cv2.threshold(gray, 240, 255, cv2.THRESH_BINARY)

# 查找轮廓
contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

for contour in contours:
    # 计算轮廓的逼近多边形
    approx = cv2.approxPolyDP(contour, 0.04 * cv2.arcLength(contour, True), True)
    
    # 区分形状
    if len(approx) == 3:
        shape = "Triangle"
    elif len(approx) == 4:
        shape = "Rectangle"
    else:
        shape = "Circle"

    # 在图像上绘制轮廓和形状名称
    cv2.drawContours(image, [contour], -1, (0, 255, 0), 2)
    cv2.putText(image, shape, (contour[0][0][0], contour[0][0][1]), cv2.FONT_HERSHEY_SIMPLEX, 
                0.5, (255, 255, 255), 2)

# 显示结果图像
cv2.imshow("Shapes", image)
cv2.waitKey(0)
cv2.destroyAllWindows()

在这里插入图片描述

4.线段长度测量

def measure_length(line,width,dis_ref):
    distance = dist.euclidean((line[0][0],line[0][1]), (line[1][0],line[1][1]))
    pixelsPerMetric = dis_ref / width
    dim = distance / pixelsPerMetric

    midpoint = ((line[0][0] + line[1][0]) // 2, (line[0][1] + line[1][1]) // 2)

    return dim,midpoint

5.角度测量

#获取两条线的角度,返回角度值与交点
def measure_angle(line1,line2):
    slope1 = (line1[1][1] - line1[0][1]) / (line1[1][0] - line1[0][0])  # 斜率1
    slope2 = (line2[1][1] - line2[0][1]) / (line2[1][0] - line2[0][0])  # 斜率2

    # 计算交点
    x_intersect = (slope1 * line1[0][0] - slope2 * line2[0][0] + line2[0][1] - line1[0][1]) / (
            slope1 - slope2)
    y_intersect = slope1 * (x_intersect - line1[0][0]) + line1[0][1]

    # 计算两条线之间的角度(弧度)
    angle_rad = np.arctan(abs((slope2 - slope1) / (1 + slope1 * slope2)))

    # 将弧度转换为角度
    angle_deg = np.degrees(angle_rad)

    angle = round(angle_deg, 1)

    return angle,(int(x_intersect), int(y_intersect))

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【离散数学】——期末刷题题库(命题逻辑)

&#x1f383;个人专栏&#xff1a; &#x1f42c; 算法设计与分析&#xff1a;算法设计与分析_IT闫的博客-CSDN博客 &#x1f433;Java基础&#xff1a;Java基础_IT闫的博客-CSDN博客 &#x1f40b;c语言&#xff1a;c语言_IT闫的博客-CSDN博客 &#x1f41f;MySQL&#xff1a…

计算机杂谈系列精讲100篇-【计算机应用】PyTorch部署及分布式训练

目录 C平台PyTorch模型部署流程 1.模型转换 1. 不支持的操作 2. 指定数据类型 2.保存序列化模型 3.C load训练好的模型 4. 执行Script Module PyTorch分布式训练 分布式并行训练概述 Pytorch分布式数据并行 手把手渐进式实战 A. 单机单卡 B. 单机多卡DP C. 多机多卡DDP D. L…

小狐狸ChatGPT付费创作系统V2.3.4独立版 +WEB端+ H5端最新去弹窗授权

ChatGPT付费创作系统V2.3.4版本优化了很多细节&#xff0c;如果使用着2.2.9版本建议没升级的必要。该版本为编译版无开源&#xff0c;2.3.X版本开始官方植入了更多的后门和更隐性的弹窗代码&#xff0c;后门及弹窗处理起来更麻烦。特别针对后台弹窗网址、暗链后门网址全部进行了…

2023年国赛试题:配置inux1 为 CA 服务器

试题内容:配置 linux1 为 CA 服务器,为 linux 主机颁发证书。证书颁发机构有 效期 10 年,公用名为 linux1.skills.lan。申请并颁发一张供 linux 服务器使用的证书,证书信息:有效期 =5 年,公用名=skills.lan, 国家=CN,省=Beijing,城市=Beijing,组织=skills,组织单位…

Java使用263和qq邮箱发邮件

一、添加依赖 <dependency><groupId>com.sun.mail</groupId><artifactId>javax.mail</artifactId><version>1.6.2</version></dependency>二、263邮箱 1&#xff0c;邮箱配置 public static void sendEmail(String host, in…

【Linux】Linux第一个小程序 --- 进度条

&#x1f466;个人主页&#xff1a;Weraphael ✍&#x1f3fb;作者简介&#xff1a;目前正在学习c和Linux还有算法 ✈️专栏&#xff1a;Linux &#x1f40b; 希望大家多多支持&#xff0c;咱一起进步&#xff01;&#x1f601; 如果文章有啥瑕疵&#xff0c;希望大佬指点一二 …

什么是量子优势?

量子优势是量子计算领域正在积极努力的里程碑&#xff0c;量子计算机可以解决最强大的非量子或经典计算机无法解决的问题。 量子是指原子和分子的尺度&#xff0c;在这个尺度上&#xff0c;我们所经历的物理定律被打破&#xff0c;并且应用了一组不同的、违反直觉的定律。量子…

微信小程序+中草药分类+爬虫+keras

目录 1 介绍2 数据爬虫3 模型训练和验证3.1 模型训练3.2 导入一张图片进行验证 4 后台flask部署5 微信小程序 1 介绍 本项目使用深度学习模型&#xff0c;训练5种中药材数据集&#xff0c;然后将其集成到微信小程序&#xff0c;通过微信小程序拍照&#xff0c;将图片传输给后端…

monorepo多项目管理主流实现方式:1.learn + yarn/npm workspace 2.pnpm

npm域级包 随着npm包越来越多&#xff0c;而且包名也只能是唯一的&#xff0c;如果一个名字被别人占了&#xff0c;那你就不能再使用这个名字&#xff1b;假设我想要开发一个utils包&#xff0c;但是张三已经发布了一个utils包&#xff0c;那我的包名就不能叫utils了&#xff…

数据分享 I 重点城市现状建筑数据,shp格式放送

数据名称: 现状建筑数据 数据格式: Shp 数据时间: 不同城市的数据时间有所不同&#xff0c;详情可搜“吧唧数据” 数据几何类型: 面 数据坐标系: WGS84坐标系 数据来源&#xff1a;网络公开数据 深圳市现状建筑数据示意图 东莞市部分镇街现状建筑数据示意图 武汉市部…

Apache Flink(一):Apache Flink是什么?

&#x1f3e1; 个人主页&#xff1a;IT贫道_大数据OLAP体系技术栈,Apache Doris,Clickhouse 技术-CSDN博客 &#x1f6a9; 私聊博主&#xff1a;加入大数据技术讨论群聊&#xff0c;获取更多大数据资料。 &#x1f514; 博主个人B栈地址&#xff1a;豹哥教你大数据的个人空间-豹…

智能优化算法应用:基于花授粉算法无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于花授粉算法无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于花授粉算法无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.花授粉算法4.实验参数设定5.算法结果6.参考文献7.…

python实现C++简易自动压行

突发奇想&#xff0c;想要将自己的c压行之后交上去。但是苦于手动压行效率太低&#xff0c;在网上搜索压行网站没有找到&#xff0c;突然发现压行不就是检查检查去个换行符吗。于是心血来潮&#xff0c;用python实现了一个简易压行程序。 首先&#xff0c;宏定义等带#的文件不…

中间件安全:JBoss 反序列化命令执行漏洞.(CVE-2017-7504)

中间件安全&#xff1a;JBoss 反序列化命令执行漏洞.&#xff08;CVE-2017-7504&#xff09; JBoss 反序列化漏洞&#xff0c;该漏洞位于 JBoss 的 HttpInvoker 组件中的 ReadOnlyAccessFilter 过滤器中&#xff0c;其 doFilter 方法在没有进行任何安全检查和限制的情况下尝试…

【LeetCode】每日一题 2023_11_28 设计前中后队列(数组/链表/双端队列)

文章目录 刷题前唠嗑题目&#xff1a;设计前中后队列题目描述代码与解题思路偷看大佬题解 结语 刷题前唠嗑 LeetCode&#xff1f;启动&#xff01;&#xff01;&#xff01; 这道题的难度&#xff0c;才是我想象中的中等题的难度好吧&#xff0c;昨天那玩意对我来说还是太难了…

【C++初阶】五、类和对象(日期类的完善、流运算符重载函数、const成员、“”取地址运算符重载)

相关代码gitee自取&#xff1a; C语言学习日记: 加油努力 (gitee.com) 接上期&#xff1a; 【C初阶】四、类和对象 &#xff08;构造函数、析构函数、拷贝构造函数、赋值运算符重载函数&#xff09;-CSDN博客 一 . 日期类的完善 此次日期类的成员函数&#xff0c;采用声明…

java List集合(ArrayList,LinkedList,Vector)

Hi i,m JinXiang ⭐ 前言 ⭐ 本篇文章主要介绍java List集合的三种实现类ArrayList&#xff0c;LinkedList&#xff0c;Vector以及部分理论知识 &#x1f349;欢迎点赞 &#x1f44d; 收藏 ⭐留言评论 &#x1f4dd;私信必回哟&#x1f601; &#x1f349;博主收将持续更新学习…

python 爬虫之 爬取网站信息并保存到文件

文章目录 前期准备探索该网页的HTML码的特点开始编写代码存入文件总的程序文件存储效果 前期准备 随便找个网站进行爬取&#xff0c;这里我选择的是(一个卖书的网站&#xff09; https://www.bookschina.com/24hour/62700000/ 我的目的是爬取这个网站的这个页面的书籍的名称以…

JAVA基础进阶(六)

一、包装类的作用 在Java中&#xff0c;包装类是一种用于将基本数据类型封装成对象的机制。 byte、short、int、long、float、double、char、boolean都是基本数据类型,不能当做对象使用。而这些基本数据类型都有对应的包装类,可以当做对象进行使用(包装类是引用数据类型)。 这…

用Sublime编写Lua脚本

大家好&#xff0c;我是阿赵。   现在很多手游项目使用lua作为热更新的代码脚本&#xff0c;我一直很喜欢用Sublime来写lua程序。喜欢使用它的原因是它的轻量化&#xff0c;因为我经常要同时打开多个项目&#xff0c;Unity和VisualStudio这些软件都比较占用电脑的性能&#x…
最新文章