【图像增强】使用 Albumentations Python 库(01)

news2024/9/24 19:13:29

目录

一、说明

二、Albumentations库

2.1 如何安装 

2.2 测试代码示例

2.3 在albumentations库中实现的所有像素级变换

2.4 空间级转换

2.5 混合级别转换

三、让我们看看上述实现中的转换。

3.1 在专辑中实现的天气相关转换

3.2 随机雨

3.3 在相册中处理非 8 位图像

3.4 在文档图像中增强文本(叠加元素)

3.5 带相册的边界框关键点旋转

3.6 绘制边界框

3.7 定义两个带有坐标和类标签的边界框

四、定义增强管道

4.1 min_area和min_visibility参数

4.2 使用 min_area 和 min_visibilty 的默认值定义增强管道

五、其它变换

5.1 半音差

5.2 D4 变换

5.3 形态变换

5.4 域适应转换

5.5 Historgram 匹配

5.6 傅里叶域适应 (FDA)

5.7 像素分布

5.8 RandomGridShuffle 随机排序

来源:


图片来源:https://github.com/albumentations-team/albumentations_examples/

一、说明

        深度学习模型需要大量高质量的训练数据才能表现良好。获得足够数量的高质量标记训练数据是很困难的。这对于图像数据尤其困难,尤其是在医疗保健等领域,这些领域可能对共享患者数据有法律限制,或者可用数据的成本可能太高。

        图像分类、对象检测、语义分割等计算机视觉任务涉及人工进行图像标记、在对象周围绘制边界框或像素标记以创建标记的图像数据集。

        图像增广是通过对可用图像进行微小更改来创建新训练图像的过程。这包括更改图像的亮度或对比度、裁剪图像的一部分、翻转或旋转原始图像等更改。使用对原始标记图像的这些转换,可以增加图像数量。标记数据的数量越多,模型过度拟合的可能性就越小。

        Albumentations 有效地实现了丰富的 Image Transform 操作,并执行 同时提供简洁而强大的图像增广界面 不同的计算机视觉任务,包括对象分类、分割、 和检测。

二、Albumentations库

Albumentations 是一个 Python 库,用于快速灵活的图像增强。Albumentations 有效地实现了丰富多样的图像转换操作,这些操作针对性能进行了优化,同时为不同的计算机视觉任务(包括对象分类、分割和检测)提供简洁而强大的图像增强接口。

2.1 如何安装 

pip install -U albumentations

2.2 测试代码示例

让我们看看代码示例来使用此库的功能

我们在下面看到的所有代码都来自其原始 GitHub 存储库和 API 文档中应用专辑的示例。

步骤 1:在 Jupyter Notebook 中导入相册和其他必需的库

import albumentations as A
import matplotlib.pyplot as plt
import cv2

步骤 2:定义增强管道。

        要定义增强管道,您需要创建 Compose 类的实例。作为 Compose 类的参数,您需要传递要应用的增强列表。对 Compose 的调用将返回一个转换函数,该函数将执行图像增强。

transform = A.Compose([
    A.RandomCrop(width=256, height=256),
    A.HorizontalFlip(p=0.5),
    A.RandomBrightnessContrast(p=0.2),
])

        要创建增强,您需要创建所需 augmentation 类的实例,并将 augmentation 参数传递给它。A.RandomCrop 接收两个参数:height 和 width。A.RandomCrop(width=256, height=256) 表示 A.RandomCrop 将获取输入图像,从中提取大小为 256 x 256 像素的随机块,然后将结果传递给管道中的下一个增强(在本例中为 A.HorizontalFlip)。

        A.HorizontalFlip 在此示例中有一个名为 p 的参数。p 是几乎所有增强都支持的特殊参数。它控制应用增强的概率。p=0.5 表示转换的概率为 50%,转换将水平翻转图像,概率为 50%,转换不会修改输入图像。

        示例中的 A.RandomBrighntessContrast 也有一个参数 p。这种增强的可能性为 20%,将更改从 A.HorizontalFlip 接收的图像的亮度和对比度。并且以 80% 的概率,它将保持接收到的图像不变。

        第 3 步:从磁盘读取图像。

        要将图像传递到增强管道,您需要从磁盘中读取它。管道期望接收 NumPy 数组形式的图像。如果是彩色图像,它应该按以下顺序有三个通道:红色、绿色、蓝色(因此是常规的 RGB 图像)。

        要从磁盘读取图像,您可以使用 OpenCV — 一种流行的图像处理库。它支持许多输入格式,并与 Albumentations 一起安装,因为 Albumentations 在后台利用该库进行大量增强。

import matplotlib.pyplot as plt
def cv2_imshow(img):
    plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
    plt.show()

image = cv2.imread("lung_mri.jpg")
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
cv2_imshow(image)

图片来源:https://www.nih.gov/sites/default/files/news-events/news-releases/2019/20191001-nhlbi-lung-th.jpg

        要将图像传递到增强管道,您需要在第 2 步调用 A.Compose 创建的转换函数。在该函数的 image 参数中,您需要传递要增强的图像。

#transform will return a dictionary with a single key image. 
#Value at that key will contain an augmented image.
transformed = transform(image=image)
transformed_image = transformed["image"]
cv2_imshow(transformed_image)

让我们在上面的肺部 MRI 图像上看到更多转换

import os
import random
import albumentations as A
import cv2
import numpy as np
from matplotlib import pyplot as plt
from skimage.color import label2rgb


BOX_COLOR = (255, 0, 0) # Red
TEXT_COLOR = (255, 255, 255) # White

#function to visualize bounding box
#The visualization function is based on 
#https://github.com/facebookresearch/Detectron/blob/master/detectron/utils/vis.py
def visualize_bbox(img, bbox, color=BOX_COLOR, thickness=2, **kwargs):
    x_min, y_min, w, h = bbox
    x_min, x_max, y_min, y_max = int(x_min), int(x_min + w), int(y_min), int(y_min + h)
    cv2.rectangle(img, (x_min, y_min), (x_max, y_max), color=color, thickness=thickness)
    return img
#function to display title text
def visualize_titles(img, bbox, title, font_thickness = 2, font_scale=0.35, **kwargs):
    x_min, y_min = bbox[:2]
    x_min = int(x_min)
    y_min = int(y_min)
    ((text_width, text_height), _) = cv2.getTextSize(title, cv2.FONT_HERSHEY_SIMPLEX, 
                                                     font_scale, font_thickness)
    cv2.rectangle(img, (x_min, y_min - int(1.3 * text_height)), 
                  (x_min + text_width, y_min), BOX_COLOR, -1)
    cv2.putText(img, title, (x_min, y_min - int(0.3 * text_height)), 
                cv2.FONT_HERSHEY_SIMPLEX, font_scale, TEXT_COLOR,
                font_thickness, lineType=cv2.LINE_AA)
    return img

#function to apply transforms and display transformed images
def augment_and_show(aug, image, mask=None, bboxes=[], categories=[], 
                     category_id_to_name=[], filename=None,
                     font_scale_orig=0.35, font_scale_aug=0.35, show_title=True, **kwargs):

    if mask is None:
        augmented = aug(image=image, bboxes=bboxes, category_ids=categories)
    else:
        augmented = aug(image=image, mask=mask, bboxes=bboxes, category_ids=categories)

    image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
    image_aug = cv2.cvtColor(augmented['image'], cv2.COLOR_BGR2RGB)

    for bbox in bboxes:
        visualize_bbox(image, bbox, **kwargs)

    for bbox in augmented['bboxes']:
        visualize_bbox(image_aug, bbox, **kwargs)

    if show_title:
        for bbox,cat_id in zip(bboxes, categories):
            visualize_titles(image, bbox, category_id_to_name[cat_id],
                             font_scale=font_scale_orig, **kwargs)
        for bbox,cat_id in zip(augmented['bboxes'], augmented['category_ids']):
            visualize_titles(image_aug, bbox, 
                             category_id_to_name[cat_id], font_scale=font_scale_aug, **kwargs)


    if mask is None:
        f, ax = plt.subplots(1, 2, figsize=(16, 8))

        ax[0].imshow(image)
        ax[0].set_title('Original image')

        ax[1].imshow(image_aug)
        ax[1].set_title('Augmented image')
    else:
        f, ax = plt.subplots(2, 2, figsize=(16, 16))

        if len(mask.shape) != 3:
            mask = label2rgb(mask, bg_label=0)
            mask_aug = label2rgb(augmented['mask'], bg_label=0)
        else:
            mask = cv2.cvtColor(mask, cv2.COLOR_BGR2RGB)
            mask_aug = cv2.cvtColor(augmented['mask'], cv2.COLOR_BGR2RGB)

        ax[0, 0].imshow(image)
        ax[0, 0].set_title('Original image')

        ax[0, 1].imshow(image_aug)
        ax[0, 1].set_title('Augmented image')

        ax[1, 0].imshow(mask, interpolation='nearest')
        ax[1, 0].set_title('Original mask')

        ax[1, 1].imshow(mask_aug, interpolation='nearest')
        ax[1, 1].set_title('Augmented mask')

    f.tight_layout()

    if filename is not None:
        f.savefig(filename)

    if mask is None:
        return augmented['image'], None, augmented['bboxes']

    return augmented['image'], augmented['mask'], augmented['bboxes']

#helper function to find a filename in a directory
def find_in_dir(dirname):
    return [os.path.join(dirname, fname) for fname in sorted(os.listdir(dirname))]

image = cv2.imread('lung_mri.jpg')


random.seed(42)

bbox_params = A.BboxParams(format='coco', label_fields=['category_ids'])

light = A.Compose([
    A.RandomBrightnessContrast(p=1),
    A.RandomGamma(p=1),
    A.CLAHE(p=1),
], p=1, bbox_params=bbox_params)

medium = A.Compose([
    A.CLAHE(p=1),
    A.HueSaturationValue(hue_shift_limit=20, sat_shift_limit=50, val_shift_limit=50, p=1),
], p=1, bbox_params=bbox_params)


strong = A.Compose([
    A.RGBShift(p=1),
     A.Blur(p=1),
     A.GaussNoise(p=1),
     A.ElasticTransform(p=1),
], p=1, bbox_params=bbox_params)



r = augment_and_show(light, image)

r = augment_and_show(medium, image)

 r  = augment_and_show(strong, image) 

2.3 在albumentations库中实现的所有像素级变换

        这些转换在像素级别应用于输入图像,并返回任何其他输入目标,如蒙版、边界框或关键点,保持不变。

  • 高级模糊
  • 模糊
  • 克拉赫
  • 频道辍学
  • ChannelShuffle (频道随机播放)
  • 色差
  • 颜色抖动
  • 离 焦
  • 缩小规模
  • 浮雕
  • 等化
  • 美国食品药品监督管理局
  • 花式PCA
  • FromFloat (从浮点数)
  • GaussNoise (高斯噪声)
  • GaussianBlur (高斯模糊)
  • 玻璃模糊
  • 直方图匹配
  • HueSaturationValue
  • ISO 诺伊斯
  • 图像压缩
  • InvertImg (反转图像)
  • 中值模糊
  • 运动模糊
  • MultiplicativeNoise (乘法噪声)
  • 正常化
  • PixelDistributionAdaptation 像素分布适应
  • PlanckianJitter
  • 色调分离
  • RGBShift
  • RandomBrightnessContrast (随机亮度对比度)
  • RandomFog (随机雾)
  • 随机伽玛
  • 随机砾石
  • 随机雨
  • RandomShadow (随机阴影)
  • 随机雪
  • 随机太阳耀斑
  • 随机音调曲线
  • 振铃过冲
  • 提高
  • 曝光
  • 飞溅
  • 超像素
  • 模板转换
  • 文本图像
  • ToFloat 浮点数
  • 到 Gray
  • ToRGB
  • 棕榈
  • UnsharpMask (取消锐化蒙版)
  • 缩放模糊

2.4 空间级转换

        下面给出了它们支持的空间级变换和目标。如果尝试将空间级转换应用于不受支持的目标,则 Albumentations 将引发错误。

2.5 混合级别转换

        将多个图像混合为一个图像的转换

三、让我们看看上述实现中的转换。

## Simple Augmentations
import random
import cv2
from matplotlib import pyplot as plt
import albumentations as A


def visualize(image):
    plt.figure(figsize=(10, 10))
    plt.axis('off')
    plt.imshow(image)


image = cv2.imread('dog_image.png')
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
visualize(image)

图片来源:https://github.com/albumentations-team/albumentations_examples/

定义一个增强,将图像传递给它并接收增强图像 我们修复随机种子以进行可视化,因此增强将始终产生相同的结果。在实际的计算机视觉管道中,在对图像应用转换之前,不应修复随机种子,因为在这种情况下,管道将始终输出相同的图像。图像增强的目的是每次使用不同的转换。

transform = A.HorizontalFlip(p=0.5)
random.seed(7)
augmented_image = transform(image=image)['image']
visualize(augmented_image)
transform = A.ShiftScaleRotate(p=0.5)
random.seed(7)
augmented_image = transform(image=image)['image']
visualize(augmented_image)
#Define an augmentation pipeline using Compose, pass the image to it and receive the augmented image

transform = A.Compose([
    A.CLAHE(),
    A.RandomRotate90(),
    A.Transpose(),
    A.ShiftScaleRotate(shift_limit=0.0625, scale_limit=0.50, rotate_limit=45, p=.75),
    A.Blur(blur_limit=3),
    A.OpticalDistortion(),
    A.GridDistortion(),
    A.HueSaturationValue(),
])
random.seed(42)
augmented_image = transform(image=image)['image']
visualize(augmented_image)
transform = A.Compose([
        A.RandomRotate90(),
        A.Flip(),
        A.Transpose(),
        A.GaussNoise(),
        A.OneOf([
            A.MotionBlur(p=.2),
            A.MedianBlur(blur_limit=3, p=0.1),
            A.Blur(blur_limit=3, p=0.1),
        ], p=0.2),
        A.ShiftScaleRotate(shift_limit=0.0625, scale_limit=0.2, rotate_limit=45, p=0.2),
        A.OneOf([
            A.OpticalDistortion(p=0.3),
            A.GridDistortion(p=.1),
        ], p=0.2),
        A.OneOf([
            A.CLAHE(clip_limit=2),
            A.RandomBrightnessContrast(),
        ], p=0.3),
        A.HueSaturationValue(p=0.3),
    ])
random.seed(42)
augmented_image = transform(image=image)['image']
visualize(augmented_image)

3.1 在专辑中实现的天气相关转换

import random 
import cv2 
from matplotlib import pyplot as plt 
import albumentations as A


def visualize(image):
    #image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
    plt.figure(figsize=(20, 10))
    plt.axis('off')
    plt.imshow(image)

image = cv2.imread('weather_example.jpg')
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
visualize(image)

3.2 随机雨

        我们修复随机种子以达到可视化目的,因此增强将始终产生相同的结果。在实际的计算机视觉管道中,在对图像应用转换之前,不应修复随机种子,因为在这种情况下,管道将始终输出相同的图像。图像增强的目的是每次使用不同的转换。

transform = A.Compose([A.RandomRain(brightness_coefficient=0.9, drop_width=1, blur_value=5, p=1)],)
#random.seed(7)
transformed = transform(image=image)
visualize(transformed['image'])
#RandomSnow

transform = A.Compose(
    [A.RandomSnow(brightness_coeff=2.5, snow_point_lower=0.3, snow_point_upper=0.5, p=1)],
)
random.seed(7)
transformed = transform(image=image)
visualize(transformed['image'])
#RandomSunFlare

transform = A.Compose(
    [A.RandomSunFlare(flare_roi=(0, 0, 1, 0.5), angle_lower=0.5, p=1)],
)
random.seed(7)
transformed = transform(image=image)
visualize(transformed['image'])
#RandomShadow

transform = A.Compose(
    [A.RandomShadow(num_shadows_lower=1, num_shadows_upper=1, shadow_dimension=5, shadow_roi=(0, 0.5, 1, 1), p=1)],
)
random.seed(7)
transformed = transform(image=image)
visualize(transformed['image'])
#RandomFog

transform = A.Compose(
    [A.RandomFog(fog_coef_lower=0.7, fog_coef_upper=0.8, alpha_coef=0.1, p=1)],
)
random.seed(7)
transformed = transform(image=image)
visualize(transformed['image'])

随机雪变换

3.3 在相册中处理非 8 位图像

        例如 16 位 TIFF 图像。卫星影像中使用 16 位影像。以下技术可应用于所有非 8 位图像(即 24 位图像、32 位图像等)。

import random
import cv2
from matplotlib import pyplot as plt
import albumentations as A


#visualize function will be a bit different for TIFF images
import numpy as np
def visualize(image):
    # Divide all values by 65535 so we can display the image using matplotlib
    image = image / np.max(image)
    plt.figure(figsize=(10, 10))
    plt.axis('off')
    plt.imshow(image)


#Read the 16-bit TIFF image from the disk
# The image is taken from http://www.brucelindbloom.com/index.html?ReferenceImages.html
# © Bruce Justin Lindbloom
image = cv2.imread('DeltaE_16bit_gamma2.2.tif', cv2.IMREAD_UNCHANGED)
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
visualize(image)
transform = A.Compose([
    A.ToFloat(max_value=65535.0),

    A.RandomRotate90(),
    A.Flip(),
    A.OneOf([
        A.MotionBlur(p=0.2),
        A.MedianBlur(blur_limit=3, p=0.1),
        A.Blur(blur_limit=3, p=0.1),
    ], p=0.2),
    A.ShiftScaleRotate(shift_limit=0.0625, scale_limit=0.2, 
                       rotate_limit=45, p=0.2),
    A.OneOf([
        A.OpticalDistortion(p=0.3),
        A.GridDistortion(p=0.1),
    ], p=0.2),
    A.HueSaturationValue(hue_shift_limit=20, sat_shift_limit=0.1, 
                         val_shift_limit=0.1, p=0.3),

    A.FromFloat(max_value=65535.0),
])

random.seed(7)
augmented = transform(image=image)
visualize(augmented['image'])

3.4 在文档图像中增强文本(叠加元素)

        管道处理 TIFF 图像和关联的 JSON 文件,这些文件描述文档图像中的文本行及其边界框 GitHub - danaaubakirova/doc-augmentation

import cv2
from matplotlib import pyplot as plt
from PIL import ImageDraw, ImageFont, Image
from pylab import *
import albumentations as A
import json


def visualize(image):
    plt.figure(figsize=(20, 10))
    plt.axis('off')
    plt.imshow(image)

def load_rgb(image_path):
    image = cv2.imread(image_path)
    return cv2.cvtColor(image, cv2.COLOR_BGR2RGB)

font_path = "LiberationSerif-Regular.ttf"
image = load_rgb("docs.png")

with open("text.json") as f:
    labels = json.load(f)
visualize(image)

transform = A.Compose([A.OverlayElements(p=1)])


def render_text(bbox_shape, text, font):
    bbox_height, bbox_width = bbox_shape

    # Create an empty RGB image with the size of the bounding box
    bbox_img = Image.new("RGB", (bbox_width, bbox_height), color="white")
    draw = ImageDraw.Draw(bbox_img)

    # Draw the text in red
    draw.text((0, 0), text, fill="red", font=font)

    return np.array(bbox_img)




bbox_indices_to_update = np.random.choice(range(len(labels["text"])), 10)
labels.keys()
image_height, image_width = image.shape[:2]
num_channels = image.shape[2] if len(image.shape) == 3 else 1


metadata = []
for index in bbox_indices_to_update:
    selected_bbox = labels["bbox"][index]

    # You may apply any transforms you want to text like 
    #random deletion, swapping words, applying synonims, etc
    text = labels["text"][index]

    left, top, width_norm, height_norm = selected_bbox

    bbox_height = int(image_height * height_norm)
    bbox_width = int(image_width * width_norm)

    font = ImageFont.truetype(font_path, int(0.90 * bbox_height))

    overlay_image = render_text((bbox_height, bbox_width), text, font)

    metadata += [
        {
            "image": overlay_image,
            "bbox": (left, top, left + width_norm, top + height_norm)
        }
    ]


transformed = transform(image=image, overlay_metadata=metadata)
visualize(transformed["image"])

transform_complex = A.Compose([A.OverlayElements(p=1),
                               A.RandomCrop(p=1, height=1024, width=1024),
                               A.PlanckianJitter(p=1),
                               A.Affine(p=1)
                              ])
transformed = transform_complex(image=image, overlay_metadata=metadata)
visualize(transformed["image"])

3.5 带相册的边界框关键点旋转

from typing import List
import albumentations as A
import cv2
import matplotlib.pyplot as plt
import numpy as np


def visualize(image: np.ndarray, keypoints: List[List[float]], 
              bboxes: List[List[float]]) -> np.ndarray:
    overlay = image.copy()
    for kp in keypoints:
        cv2.circle(overlay, (int(kp[0]), int(kp[1])), 20, 
                   (0, 200, 200), thickness=2, lineType=cv2.LINE_AA)

    for box in bboxes:
        cv2.rectangle(overlay, (int(box[0]), int(box[1])), 
                      (int(box[2]), int(box[3])), (200, 0, 0), thickness=2)

    return overlay


def main() -> None:
    image = cv2.imread("image_1.jpg")

    keypoints = cv2.goodFeaturesToTrack(
        cv2.cvtColor(image, cv2.COLOR_RGB2GRAY), maxCorners=100, 
        qualityLevel=0.5, minDistance=5
    ).squeeze(1)

    bboxes = [(kp[0] - 10, kp[1] - 10, kp[0] + 10, kp[1] + 10) for kp in keypoints]

    disp_image = visualize(image, keypoints, bboxes)
    plt.figure(figsize=(10, 10))
    plt.imshow(cv2.cvtColor(disp_image, cv2.COLOR_RGB2BGR))
    plt.tight_layout()
    plt.show()

    aug = A.Compose(
        [A.ShiftScaleRotate(scale_limit=0.1, shift_limit=0.2, 
                            rotate_limit=10, always_apply=True)],
        bbox_params=A.BboxParams(format="pascal_voc", label_fields=["bbox_labels"]),
        keypoint_params=A.KeypointParams(format="xy"),
    )

    for _i in range(10):
        data = aug(image=image, keypoints=keypoints, bboxes=bboxes, 
                   bbox_labels=np.ones(len(bboxes)))

        aug_image = data["image"]
        aug_image = visualize(aug_image, data["keypoints"], data["bboxes"])

        plt.figure(figsize=(10, 10))
        plt.imshow(cv2.cvtColor(aug_image, cv2.COLOR_RGB2BGR))
        plt.tight_layout()
        plt.show()

if __name__ == "__main__":
    main()

3.6 绘制边界框

import random
import cv2
from matplotlib import pyplot as plt
import albumentations as A

可视化功能基于 Detectron/detectron/utils/vis.py at main · facebookresearch/Detectron · GitHub

BOX_COLOR = (255, 0, 0) # Red
TEXT_COLOR = (255, 255, 255) # White


def visualize_bbox(img, bbox, class_name, color=BOX_COLOR, thickness=2):
    """Visualizes a single bounding box on the image"""
    x_min, y_min, w, h = bbox
    x_min, x_max, y_min, y_max = int(x_min), int(x_min + w), int(y_min), int(y_min + h)

    cv2.rectangle(img, (x_min, y_min), (x_max, y_max), color=color, thickness=thickness)

    ((text_width, text_height), _) = cv2.getTextSize(class_name, cv2.FONT_HERSHEY_SIMPLEX, 0.35, 1)
    cv2.rectangle(img, (x_min, y_min - int(1.3 * text_height)), 
                  (x_min + text_width, y_min), BOX_COLOR, -1)
    cv2.putText(
        img,
        text=class_name,
        org=(x_min, y_min - int(0.3 * text_height)),
        fontFace=cv2.FONT_HERSHEY_SIMPLEX,
        fontScale=0.35,
        color=TEXT_COLOR,
        lineType=cv2.LINE_AA,
    )
    return img


def visualize(image, bboxes, category_ids, category_id_to_name):
    img = image.copy()
    for bbox, category_id in zip(bboxes, category_ids):
        class_name = category_id_to_name[category_id]
        img = visualize_bbox(img, bbox, class_name)
    plt.figure(figsize=(12, 12))
    plt.axis('off')
    plt.imshow(img)

在此示例中,我们将使用 COCO 数据集中的图像,该图像具有两个关联的边界框。该图片可在 COCO - Common Objects in Context

image = cv2.imread('000000386298.jpg')
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)

3.7 定义两个带有坐标和类标签的边界框

        这些边界框的坐标使用 coco 格式声明。每个边界框都使用四个值 [x_min、y_min、宽度、高度] 进行描述。关于边界框坐标不同格式的详细说明,请参考 边界框 — Bounding boxes augmentation for object detection - Albumentations Documentation 的文档文章。

bboxes = [[5.66, 138.95, 147.09, 164.88], [366.7, 80.84, 132.8, 181.84]]
category_ids = [17, 18]

# We will use the mapping from category_id to the class name
# to visualize the class label for the bounding box on the image
category_id_to_name = {17: 'cat', 18: 'dog'}


#Visuaize the original image with bounding boxes
visualize(image, bboxes, category_ids, category_id_to_name)

四、定义增强管道

        要创建适用于边界框的增强管道,您需要将 BboxParams 的一个实例传递给 Compose。在 BboxParams 中,您需要指定边界框的坐标格式以及可选的一些其他参数。有关 BboxParams 的详细说明,请参阅有关边界框 — Bounding boxes augmentation for object detection - Albumentations Documentation 的文档文章。

transform = A.Compose(
    [A.HorizontalFlip(p=0.5)],
    bbox_params=A.BboxParams(format='coco', label_fields=['category_ids']),
)



random.seed(7)
transformed = transform(image=image, bboxes=bboxes, category_ids=category_ids)
visualize(
    transformed['image'],
    transformed['bboxes'],
    transformed['category_ids'],
    category_id_to_name,
)
transform = A.Compose(
    [A.ShiftScaleRotate(p=0.5)],
    bbox_params=A.BboxParams(format='coco', label_fields=['category_ids']),
)

random.seed(7)
transformed = transform(image=image, bboxes=bboxes, category_ids=category_ids)
visualize(
    transformed['image'],
    transformed['bboxes'],
    transformed['category_ids'],
    category_id_to_name,
)
#Define a complex augmentation piepline

transform = A.Compose([
        A.HorizontalFlip(p=0.5),
        A.ShiftScaleRotate(p=0.5),
        A.RandomBrightnessContrast(p=0.3),
        A.RGBShift(r_shift_limit=30, g_shift_limit=30, b_shift_limit=30, p=0.3),
    ],
    bbox_params=A.BboxParams(format='coco', label_fields=['category_ids']),
)

random.seed(7)
transformed = transform(image=image, bboxes=bboxes, category_ids=category_ids)
visualize(
    transformed['image'],
    transformed['bboxes'],
    transformed['category_ids'],
    category_id_to_name,
)

4.1 min_area和min_visibility参数

        如果应用空间增强,则边界框的大小可能会更改,例如,在裁剪图像的一部分或调整图像大小时。

        min_area 和 min_visibility 参数控制 Albumentations 应对增强的边界框执行的操作,如果其大小在增强后发生了变化。如果应用空间增强,则边界框的大小可能会更改,例如,在裁剪图像的一部分或调整图像大小时。

        min_area 是以像素为单位的值。如果增强后边界框的面积小于 min_area,则 Albumentations 将删除该框。因此,返回的增强边界框列表将不包含该边界框。

min_visibility 是介于 0 和 1 之间的值。如果增强后的边界框区域与增强前的边界框面积之比小于 min_visibility,则 Albumentations 将丢弃该框。因此,如果增强过程切掉了大部分边界框,则该框将不会出现在返回的增强边界框列表中。

4.2 使用 min_area 和 min_visibilty 的默认值定义增强管道

如果不传递 min_area 和 min_visibility 参数,则 Albumentations 将使用 0 作为它们的默认值。

transform = A.Compose(
    [A.CenterCrop(height=280, width=280, p=1)],
    bbox_params=A.BboxParams(format='coco', label_fields=['category_ids']),
)

transformed = transform(image=image, bboxes=bboxes, category_ids=category_ids)
visualize(
    transformed['image'],
    transformed['bboxes'],
    transformed['category_ids'],
    category_id_to_name,
)

五、从数学模型对变换分类

5.1 半音差

import cv2
from matplotlib import pyplot as plt
import cv2

import albumentations as A

def visualize(image):
    plt.figure(figsize=(10, 5))
    plt.axis('off')
    plt.imshow(image)

def load_rgb(image_path):
    image = cv2.imread(image_path)
    return cv2.cvtColor(image, cv2.COLOR_BGR2RGB)


img_path = "alina_rossoshanska.jpeg"
img = load_rgb(img_path)
visualize(img)

#Red-blue mode

transform = A.Compose([A.ChromaticAberration(mode="red_blue", 
                                             primary_distortion_limit=0.5, 
                                             secondary_distortion_limit=0.1, p=1)])

plt.figure(figsize=(15, 10))

num_images = 12

# Loop through the list of images and plot them with subplot
for i in range(num_images):
    transformed_image = transform(image = img)["image"]
    plt.subplot(4, 3, i + 1)
    plt.imshow(transformed_image)
    plt.axis('off')

plt.tight_layout()
plt.show()

5.2 D4 变换

        Geomatric 变换是使用最广泛的增强。主要是因为他们没有在原始数据分布之外获取数据,并且因为他们有直觉”。

D4 变换将原始图像映射到 8 种状态之一。

  • e — 身份。原始图像
  • r90 — 旋转 90 度
  • r180 — 旋转 180 度,等于 v * h = h * v
  • r270 — 旋转 270 度
  • v — 垂直翻转
  • hvt — 跨对角线的反射,等于 t * v * h 或 t * rot180
  • h — 水平翻转
  • t — 反射活动对角线

相同的转换可以更方便地表示为:

A.Compose([A.HorizonatalFlip(p=0.5), A.RandomRotate90(p=1)])

此变换在影像数据没有首选方向的情况下非常有用:

例如:医学图像、俯视无人机和卫星图像。它适用于:图像、蒙版、关键点、边界框

import json
import hashlib
import random
import numpy as np
import cv2
from matplotlib import pyplot as plt
import albumentations as A



BOX_COLOR = (255, 0, 0)
TEXT_COLOR = (255, 255, 255)
KEYPOINT_COLOR = (0, 255, 0)

def visualize_bbox(img, bbox, class_name, bbox_color=BOX_COLOR, thickness=1):
    """Visualizes a single bounding box on the image"""
    x_min, y_min, x_max, y_max = (int(x) for x in bbox)
    cv2.rectangle(img, (x_min, y_min), (x_max, y_max), 
                  color=bbox_color, thickness=thickness)

    ((text_width, text_height), _) = cv2.getTextSize(class_name, 
                                                     cv2.FONT_HERSHEY_SIMPLEX, 0.35, 1)
    cv2.rectangle(img, (x_min, y_min - int(1.3 * text_height)), 
                  (x_min + text_width, y_min), bbox_color, -1)
    cv2.putText(
        img,
        text=class_name,
        org=(x_min, y_min - int(0.3 * text_height)),
        fontFace=cv2.FONT_HERSHEY_SIMPLEX,
        fontScale=0.35,
        color=TEXT_COLOR,
        lineType=cv2.LINE_AA,
    )
    return img

def vis_keypoints(image, keypoints, color=KEYPOINT_COLOR, diameter=3):
    image = image.copy()
    for (x, y) in keypoints:
        cv2.circle(image, (int(x), int(y)), diameter, color, -1)
    return image

def visualize_one(image, bboxes, keypoints, category_ids, category_id_to_name, mask):
    # Create a copy of the image to draw on
    img = image.copy()

    # Apply each bounding box and corresponding category ID
    for bbox, category_id in zip(bboxes, category_ids):
        class_name = category_id_to_name[category_id]
        img = visualize_bbox(img, bbox, class_name)

    # Apply keypoints if provided
    if keypoints:
        img = vis_keypoints(img, keypoints)

    # Setup plot
    fig, ax = plt.subplots(1, 2, figsize=(6, 3))

    # Show the image with annotations
    ax[0].imshow(img)    
    ax[0].axis('off')

    # Show the mask
    ax[1].imshow(mask, cmap='gray')    
    ax[1].axis('off')

    plt.tight_layout()
    plt.show()

     

def visualize(images, bboxes_list, keypoints_list, 
              category_ids_list, category_id_to_name, masks):
    if len(images) != 8:
        raise ValueError("This function is specifically designed to handle exactly 8 images.")

    num_rows = 4
    num_cols = 4
    
    fig, axs = plt.subplots(num_cols, num_rows, figsize=(20, 20)) 

    for idx, (image, bboxes, keypoints, category_ids, mask) in enumerate(zip(images,
                                                                             bboxes_list, 
                                                                             keypoints_list, 
                                                                             category_ids_list, 
                                                                             masks)):
        img = image.copy()

        # Process each image: draw bounding boxes and keypoints
        for bbox, category_id in zip(bboxes, category_ids):
            class_name = category_id_to_name[category_id]
            img = visualize_bbox(img, bbox, class_name)

        if keypoints:
            img = vis_keypoints(img, keypoints)

        # Calculate subplot indices
        row_index = (idx * 2) // num_rows  # Each pair takes two columns in one row
        col_index_image = (idx * 2) % num_cols  # Image at even index
        col_index_mask = (idx * 2 + 1) % num_cols  # Mask at odd index right after image

        # Plot the processed image
        img_ax = axs[row_index, col_index_image]
        img_ax.imshow(img)        
        img_ax.axis('off')

        # Plot the corresponding mask
        mask_ax = axs[row_index, col_index_mask]
        mask_ax.imshow(mask, cmap='gray')        
        mask_ax.axis('off')

    plt.tight_layout()
    plt.show()

with open("road_labels.json") as f:
    labels = json.load(f)

bboxes = labels["bboxes"]
keypoints = labels["keypoints"]

bgr_image = cv2.imread("road.jpeg")
image = cv2.cvtColor(bgr_image, cv2.COLOR_BGR2RGB)

mask = cv2.imread("road.png", 0)

# In this example we use only one class, hence category_ids is list equal 
#to the number of bounding boxes with only one value
category_ids = [1] * len(labels["bboxes"])
category_id_to_name = {1: "car"}

visualize_one(image, bboxes, keypoints, category_ids, category_id_to_name, mask)

transform = A.Compose([
    A.CenterCrop(height=512, width=256, p=1),
    A.D4(p=1)],
                     bbox_params=A.BboxParams(format='pascal_voc', 
                                              label_fields=['category_ids']),
                     keypoint_params=A.KeypointParams(format='xy'))

transformed = transform(image=image, bboxes=bboxes, 
                        category_ids=category_ids, keypoints=keypoints, mask=mask)

def get_hash(image):
    image_bytes = image.tobytes()
    hash_md5 = hashlib.md5()
    hash_md5.update(image_bytes)    
    return hash_md5.hexdigest()

transformations_dict = {}

for _ in range(80):
    transformed = transform(image=image, bboxes=bboxes, 
                            category_ids=category_ids, keypoints=keypoints, mask=mask)
    image_hash = get_hash(transformed["image"])
    
    if image_hash in transformations_dict:
        transformations_dict[image_hash]['count'] += 1
    else:
        transformations_dict[image_hash] = {
            "count": 1,
            "transformed": transformed
        }
#The transform generates all 8 possible variants with the same probability, including identity transform
len(transformations_dict)
for key in transformations_dict:
    print(key, transformations_dict[key]["count"])
transformed_list = [value["transformed"] for value in transformations_dict.values()]



images = [x["image"] for x in transformed_list]
masks = [x["mask"] for x in transformed_list]
bboxes_list = [x["bboxes"] for x in transformed_list]
keypoints_list = [x["keypoints"] for x in transformed_list]


category_ids_list = [[1] * len(x["bboxes"]) for x in transformed_list]
category_id_to_name = {1: "car"}


visualize(images, bboxes_list, keypoints_list, 
          category_ids_list, category_id_to_name, masks)

5.3 形态变换

import random

import cv2
from matplotlib import pyplot as plt

import albumentations as A

def visualize(image):
    plt.figure(figsize=(10, 5))
    plt.axis('off')
    plt.imshow(image)

def load_rgb(image_path):
    image = cv2.imread(image_path)
    return cv2.cvtColor(image, cv2.COLOR_BGR2RGB)


img_path = "scan.jpeg"
img = load_rgb(img_path)
visualize(img)

#Dilation expands the white (foreground) regions in a binary or grayscale image.
transform = A.Compose([A.Morphological(p=1, scale=(2, 3), operation='dilation')], p=1)
transformed = transform(image=img)
visualize(transformed["image"])
#Erosion shrinks the white (foreground) regions in a binary or grayscale image.
transform = A.Compose([A.Morphological(p=1, scale=(2, 3), operation='erosion')], p=1)
transformed = transform(image=img)
visualize(transformed["image"])

5.4 域适应转换

DAT 是不使用神经网络的样式迁移。生成的图像看起来并不理想,但可以在合理的时间内动态生成。

import random

import cv2
from matplotlib import pyplot as plt
from pathlib import Path
import numpy as np
import cv2

import albumentations as A

def visualize(image):
    plt.figure(figsize=(10, 5))
    plt.axis('off')
    plt.imshow(image)

def load_rgb(image_path):
    image = cv2.imread(image_path)
    return cv2.cvtColor(image, cv2.COLOR_BGR2RGB)

image1 = load_rgb("park1.png")
image2 = load_rgb("rain2.png")

visualize(image1)

visualize(image2)

5.5 Historgram 匹配

此过程调整输入图像的像素值,使其直方图与参考图像的直方图对齐。在处理多通道图像时,如果输入图像和参考图像的通道数相同,则每个通道的这种对齐都是单独进行的。

transform = A.Compose([A.HistogramMatching(reference_images=[image2], 
                                           read_fn = lambda x: x, 
                                           p=1,
                                           blend_ratio=(0.3, 0.3)
                                          )], p=1)
     
transformed = transform(image=image1)["image"]
visualize(transformed)

5.6 傅里叶域适应 (FDA)

        傅里叶域适应 (FDA) 用于在无监督域适应 (UDA) 的上下文中进行简单的“样式转移”。FDA 操纵图像的频率分量以减少源数据集和目标数据集之间的域差距,有效地使一个域中的图像与另一个域中的图像非常相似,而不会改变其语义内容。

        在训练 (源) 和测试 (目标) 图像来自不同分布的情况下,例如合成图像与真实图像,或昼夜场景,这种转换特别有用。与可能需要复杂对抗训练的传统域适应方法不同,FDA 通过在源图像和目标图像之间交换傅里叶变换的低频分量来实现域对齐。该技术已被证明可以提高模型在目标域上的性能,特别是对于语义分割等任务,而无需对域不变性进行额外的训练。

transform = A.Compose([A.FDA(reference_images=[image1], 
                             read_fn = lambda x: x, p=1, beta_limit=(0.2, 0.2))], p=1)
transformed = transform(image=image1)["image"]
visualize(transformed)

5.7 像素分布

        通过将输入图像的像素值分布与参考图像的像素值分布对齐来执行像素级域自适应。此过程涉及将简单的统计信息(例如 PCA、StandardScaler 或 MinMaxScaler)拟合到原始图像和参考图像,使用在其上训练的变换来转换原始图像,然后使用拟合在参考图像上的变换应用反向变换。其结果是经过改编的图像,它保留了原始内容,同时模仿了参考域的像素值分布。

        该过程可以可视化为两个主要步骤:

  • 使用选定的转换将原始图像调整为标准分布空间。
  • 通过应用拟合到参考图像上的变换的逆函数,将调整后的图像移动到参考图像的分布空间中。

        该技术在需要协调来自不同领域的图像(例如,合成图像与真实图像、昼夜场景)以在图像处理任务中获得更好的一致性或性能的情况下特别有用。

transform = A.Compose([A.PixelDistributionAdaptation(reference_images=[image1], 
                                                     read_fn = lambda x: x, p=1,  transform_type="pca")], p=1)

transformed = transform(image=image1)["image"]
visualize(transformed)
beta = 0.1

height, width = image1.shape[:2]
border = int(np.floor(min(height, width) * beta))
center_y, center_x = height // 2, width // 2

# Define region for amplitude substitution
y1, y2 = center_y - border, center_y + border

x1, x2 = center_x - border, center_x + border

x1, x2, y1, y2
     
(205, 307, 205, 307)

def low_freq_mutate_np(amp_src, amp_trg, L, h, w):
    b = int(np.floor(min(h, w) * L))
    c_h, c_w = h // 2, w // 2
    h1, h2 = max(0, c_h - b), min(c_h + b, h - 1)
    w1, w2 = max(0, c_w - b), min(c_w + b, w - 1)
    amp_src[h1:h2, w1:w2] = amp_trg[h1:h2, w1:w2]
    return amp_src

def fourier_domain_adaptation(src_img, trg_img, beta=0.1):
    assert src_img.shape == trg_img.shape, "Source and target images must have the same shape."
    src_img = src_img.astype(np.float32)
    trg_img = trg_img.astype(np.float32)

    height, width, num_channels = src_img.shape
    
    # Prepare container for the output image
    src_in_trg = np.zeros_like(src_img)
    
    for c in range(num_channels):
        # Perform FFT on each channel
        fft_src = np.fft.fft2(src_img[:, :, c])
        fft_trg = np.fft.fft2(trg_img[:, :, c])
        
        # Shift the zero frequency component to the center
        fft_src_shifted = np.fft.fftshift(fft_src)
        fft_trg_shifted = np.fft.fftshift(fft_trg)
        
        # Extract amplitude and phase
        amp_src, pha_src = np.abs(fft_src_shifted), np.angle(fft_src_shifted)
        amp_trg = np.abs(fft_trg_shifted)
        
        # Mutate the amplitude part of the source with the target
        
        mutated_amp = low_freq_mutate_np(amp_src.copy(), amp_trg, beta, height, width)
        
        # Combine the mutated amplitude with the original phase
        fft_src_mutated = np.fft.ifftshift(mutated_amp * np.exp(1j * pha_src))
        
        # Perform inverse FFT
        src_in_trg_channel = np.fft.ifft2(fft_src_mutated)
        
        # Store the result in the corresponding channel of the output image
        src_in_trg[:, :, c] = np.real(src_in_trg_channel)
        
    return np.clip(src_in_trg, 0, 255)

visualize(fourier_domain_adaptation(image2, image1, 0.01).astype(np.uint8))

5.8 RandomGridShuffle 随机排序

        此转换将图像划分为网格,然后根据随机映射排列这些网格单元格。

        当只有微特征对模型很重要时,它可能很有用,而记住全局结构可能是有害的。

例如:

  • 根据手机后处理算法生成的微伪影(而不是照片的语义特征)来识别用于拍照的手机类型。
  • 根据皮肤图像识别压力、葡萄糖、水合作用水平。
import random
import numpy as np
import cv2
from matplotlib import pyplot as plt
import albumentations as A
import json

KEYPOINT_COLOR = (0, 255, 0)

def vis_keypoints(image, keypoints, color=KEYPOINT_COLOR, diameter=3):
    image = image.copy()
    for (x, y) in keypoints:
        cv2.circle(image, (int(x), int(y)), diameter, color, -1)
    return image

def visualize(image, mask, keypoints):
    # Create a copy of the image to draw on
    img = image.copy()

    # Apply keypoints if provided
    if keypoints:
        img = vis_keypoints(img, keypoints)

    # Setup plot
    fig, ax = plt.subplots(1, 2, figsize=(10, 5))

    # Show the image with annotations
    ax[0].imshow(img)    
    ax[0].axis('off')

    # Show the mask
    ax[1].imshow(mask, cmap='gray')    
    ax[1].axis('off')

    plt.tight_layout()
    plt.show()




with open("road_labels.json") as f:
    labels = json.load(f)

keypoints = labels["keypoints"]

bgr_image = cv2.imread("road.jpeg")
image = cv2.cvtColor(bgr_image, cv2.COLOR_BGR2RGB)

mask = cv2.imread("road.png", 0)

visualize(image, mask, keypoints)

transform = A.Compose([A.RandomGridShuffle(grid=(2, 2), p=1)],
                      keypoint_params=A.KeypointParams(format='xy'))
transformed = transform(image=image, keypoints=keypoints, mask=mask)
visualize(transformed["image"], transformed["mask"], transformed["keypoints"])
transform = A.Compose([A.RandomGridShuffle(grid=(3, 3), p=1)], 
                      keypoint_params=A.KeypointParams(format='xy'))
transformed = transform(image=image, keypoints=keypoints, mask=mask)
visualize(transformed["image"], transformed["mask"], transformed["keypoints"])
transform = A.Compose([A.RandomGridShuffle(grid=(5, 7), p=1)],
                      keypoint_params=A.KeypointParams(format='xy'))
transformed = transform(image=image, keypoints=keypoints, mask=mask)
visualize(transformed["image"], transformed["mask"], transformed["keypoints"])

来源:

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

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

相关文章

如何优雅的实现CRUD,包含微信小程序,API,HTML的表单(一)

前言 在开发实际项目中,其实CRUD的代码量并不小,最近要做一个小程序项目,由于涉及表单的东西比较多,就萌生了一个想法,小程序的写法不是和VUE类似,就是数据绑定,模块么!那就来一个动…

【vue3|第26期】Vue3 中的 useRoute 与 router.currentRoute.value:选择正确的路由访问方式

日期:2024年8月22日 作者:Commas 签名:(ง •_•)ง 积跬步以致千里,积小流以成江海…… 注释:如果您觉在这里插入代码片得有所帮助,帮忙点个赞,也可以关注我,我们一起成长;如果有不…

推荐4款2024年专业的电脑远程控制软件。

为了能够打破空间的限制,远程控制工具被越来越多的人使用。它们可以帮助提高工作效率,方便远程技术支持等。今天,就让我们一起来了解一下网上比较火的4款远程控制电脑的软件。 1、向日葵 直达链接:https://down.oray.…

如何使用python脚本爬取微信公众号文章?

1、什么是爬虫? 在座的各位可能经常听到一个词,叫“爬虫”,这是一种能够悄无声息地将网站数据下载至本地设备的程序。利用爬虫,您无需亲自访问特定网站,逐个点击并手动下载所需数据。相反,爬虫能够全自动地…

FL Studio24苹果mac电脑破解绿色版安装包下载

FL Studio 24最新版本,这可不仅仅是一个音乐制作软件的升级,它是音乐创作爱好者的福音,是专业制作人的心头好。那么,它究竟有哪些魔力,能让这么多人为之疯狂呢? 我们来看看它的界面。FL Studio 24的界面设…

XGBoost中正则化的9个超参数

正则化是一种强大的技术,通过防止过拟合来提高模型性能。本文将探索各种XGBoost中的正则化方法及其优势。 为什么正则化在XGBoost中很重要? XGBoost是一种以其在各种机器学习任务中的效率和性能而闻名的强大算法。像任何其他复杂模型一样,它可能会过拟合,特别是在处理噪声数据…

x-cmd mod | x scoop - Windows 开源包管理工具

目录 介绍主要特点例子子命令 介绍 scoop 是 windows 的第三方包管理工具,与 winget, choco, chocolatey 类似。 本模块在 scoop 的基础上做了增强,使其可与 shell 无缝集成,并提供更多的功能。 主要特点 自动下载: 通过调用 S…

汇编语言:cmp、je、jne、jb、jnb、ja、jna 指令

一. cmp 指令 1. cmp 指令功能 cmp (compare) 是比较指令,cmp 的功能相当于减法指令,只是不保存结果,但会根据结果对标志寄存器进行设置,其它相关指令就可以通过识别这些被影响的标志寄存器的位来得知比较结果。 2. cmp指…

python爬虫:selenium+browsermobproxy实现浏览器请求抓取(模块安装详解)

前言 本来很多场景用beautiful和requests就能解决的&#xff0c;但是最近发现了某些网站会使用<link>来链接网页信息&#xff0c;让我没办法通过requests获取页面的具体内容&#xff1b;并且接口也加入了某种token的生成方案&#xff0c;导致我无从下手。 因此&#xff0…

Scrapy 分布式爬虫框架 Scrapy-Redis

github官网代码示例&#xff1a;https://github.com/rmax/scrapy-redis/blob/master/example-project/example/spiders/myspider_redis.py 什么是 Scrapy-Redis Scrapy-Redis 是一个基于 Scrapy 的扩展&#xff0c;用于实现分布式爬虫。它利用 Redis 作为分布式队列来共享待爬…

.NET_web前端框架_layui_栅格布局

基础概念 layui:用于简化前端编写的框架。响应式布局&#xff08;Responsive Layout&#xff09;:一种网页设计方法&#xff0c;使网页能够根据不同设备的屏幕尺寸和分辨率自动调整其内容和布局。栅格布局&#xff08;Grid Layout&#xff09;:一种网页设计布局方法&#xff0c…

计算机毕业设计选题推荐-OA办公管理系统-Java/Python项目实战

✨作者主页&#xff1a;IT毕设梦工厂✨ 个人简介&#xff1a;曾从事计算机专业培训教学&#xff0c;擅长Java、Python、微信小程序、Golang、安卓Android等项目实战。接项目定制开发、代码讲解、答辩教学、文档编写、降重等。 ☑文末获取源码☑ 精彩专栏推荐⬇⬇⬇ Java项目 Py…

【IEEE出版,连续7年稳定发表】第八届电气、机械与计算机工程国际学术会议(ICEMCE 2024,10月25-27)

由西京学院主办&#xff0c;AEIC学术交流中心协办&#xff0c;中国科学技术大学、深圳大学、浙江工业大学等校联合支持的第八届电气、机械与计算机工程国际学术会议&#xff08;ICEMCE 2024&#xff09;将于2024年10月25日至27日在西安举办。 本次会议主要围绕“电气”、"…

电脑文件自动加解密如何实现?3个方法教会你!

电脑文件的自动加解密是一项非常实用的功能&#xff0c;可以帮助确保数据的安全性。 以下是三种实现电脑文件自动加解密的方法&#xff1a; 方法一&#xff1a;使用操作系统自带的加密功能 Windows BitLocker&#xff1a; 启用BitLocker&#xff1a;在Windows系统中&#xf…

SpringBoot 项目——抽奖系统

本项目主要实现的功能是&#xff1a;主要服务于管理员用户&#xff0c;其可圈选奖品&#xff0c;人员来创建抽奖活动&#xff0c;并进行在线抽奖&#xff0c;并可通过短信或邮件的方式通知中奖者&#xff0c;同时普通用户可查看已结束的抽奖活动的中奖结果&#xff1b; 一、项…

ViT篇外:NVIDIA Llama-3.1-Minitron 4B

相关阅读&#xff1a; ViT&#xff1a;3 Compact Architecture MobileLLM&#xff1a;“苗条”的模型比较好&#xff01; 大家也许会很好奇为什么在ViT章节插入了NVIDIA Llama-3.1-Minitron 4B&#xff0c;ViT因为应用场景的特殊性所以都寄希望于高效率的模型&#xff0c;因…

【C语言】浮点型数据在内存中的储存

浮点型数据在内存中的储存 文章目录 浮点型数据在内存中的储存引例概念提出浮点型数据储存规定对于有效数字M的特别规定对于指数E的特别规定指数E的储存指数E的读取 利用规则解释原因 在之前学习过整形数据在内存中的储存后&#xff0c;浮点型数据在内存中的储存又会怎样呢&…

AI辅助论文写作已成大趋势,这些AI工具分享给你

近年来&#xff0c;人工智能语言模型迅速发展&#xff0c;特别是在美国人工智能研究实验室 OpenAI 于 2022 年 11 月发布了聊天机器人 ChatGPT 后&#xff0c;引发了全球范围内的广泛讨论。人们惊叹着一个新的人工智能时代已经到来&#xff0c;预示着许多工作将被这类机器人所取…

二叉树刷题(1)

二叉树题目讲解&#xff08;1&#xff09; 一、构建二叉树并且遍历&#xff08;1&#xff09;思路&#xff08;2&#xff09;代码 二、对称二叉树1、思路2、代码 三、相同的树1、思路2、代码 四、单值二叉树1、思路2、代码 五、另一棵树的子树1、思路2、代码 一、构建二叉树并且…

【Rust日报】一本新书:黑帽Rust

2024 Rust中国大会大会将于 9 月 07 日 - 08 日在上海举办。精彩议题逐步放出中&#xff0c;欢迎大家面对面交流。 2024 Rust中国大会报名链接暨第一批精彩演讲主题介绍 2024 Rust中国大会第二批精彩演讲主题列表 2024 Rust中国大会第三批精彩演讲主题列表 马尔科夫文本生成算法…