深度學習圖像預處理:統一輸入圖像尺寸方案

在實際訓練中,最常見也最簡單的做法,就是在送入網絡前把所有圖片「變形」到同一個分辨率(比如 256×256 或 224×224),或者先裁剪/填充成同樣大小。具體而言,可以分成以下幾類方案:

一、圖像分類


1. 直接縮放(Resize)

from torchvision import transformstransform = transforms.Compose([transforms.Resize((256, 256)),   # 不保留長寬比,強行拉伸transforms.ToTensor(),transforms.Normalize(mean, std),
])

優點:實現最簡單、速度最快。
缺點:會改變圖片的長寬比,可能帶來形變,對模型性能略有影響。


2. 縮放+中心/隨機裁剪(Resize + Crop)

transform = transforms.Compose([transforms.Resize(256),               # 保留長寬比,將短邊縮放到256transforms.CenterCrop(224),           # 或 RandomCrop(224)transforms.ToTensor(),transforms.Normalize(mean, std),
])

流程:先把短邊縮放到固定值(如 256 ),長邊按比例變化,然后再在中心(或隨機位置)裁剪出 224×224 的小塊。
優點:保留了部分原始長寬比信息;RandomCrop還帶來數據增強效果。
缺點:如果目標物體剛好出現在被裁掉的區域,會導致信息丟失。


3. 隨機縮放+裁剪(RandomResizedCrop)

transform = transforms.Compose([transforms.RandomResizedCrop(size=224,scale=(0.8, 1.0),      # 隨機裁出面積占原圖的80%~100%ratio=(3/4, 4/3)       # 隨機裁出長寬比范圍),transforms.RandomHorizontalFlip(),transforms.ToTensor(),transforms.Normalize(mean, std),
])

原理:先隨機在原圖上裁一個區域(面積和長寬比都隨機),再縮放到固定大小。
優點:兼顧數據增強和固定輸入大小,常用于 ImageNet 級別的訓練。
缺點:對小物體定位不友好,如果裁得太小可能把主體裁走。


4. 填充(Padding)后縮放

from PIL import ImageOpsdef pad_to_square(img, fill=0):w, h = img.sizepad = (max(h-w,0)//2, max(w-h,0)//2,max(h-w,0)-max(h-w,0)//2, max(w-h,0)-max(h-w,0)//2)return ImageOps.expand(img, pad, fill)transform = transforms.Compose([transforms.Lambda(pad_to_square),     # 填充為正方形transforms.Resize((256,256)),transforms.ToTensor(),transforms.Normalize(mean,std),
])

用途:先把圖片填充成正方形(padding),再統一縮放;可保留原始物體比例,不會變形。
缺點:padding 部分引入了無效像素,浪費計算。


5. 自適應池化——支持任意輸入尺寸

如果網絡里最后用的是全局平均池化(nn.AdaptiveAvgPool2d((1,1)))而不是全連接層,那么理論上就可以接受任意分辨率的輸入:

class SimpleCNN(nn.Module):def __init__(self, num_classes=2):super().__init__()self.features = nn.Sequential(# … 多層卷積+BN+ReLU …)# 全局自適應池化,輸出固定 (batch, C, 1, 1)self.global_pool = nn.AdaptiveAvgPool2d((1,1))self.classifier = nn.Linear(C, num_classes)def forward(self, x):x = self.features(x)x = self.global_pool(x)x = x.view(x.size(0), -1)return self.classifier(x)

優點:網絡本身對輸入尺寸不敏感,可以直接給不同分辨率圖;實際上很多 modern 結構(如 ResNet)就是這樣做的。
缺點:當輸入分辨率變化很大時,提取到的特征尺度也會差異較大,訓練和推理時的 batch 大小、顯存使用也會不一致。


小結

  1. 最常用 的是先統一縮放(Resize)或縮放+裁剪(Resize+Center/RandomCrop),這樣既簡單又有效。

  2. 進階增強 可以用 RandomResizedCrop,同時帶來固定輸入大小和更多的數據增強。

  3. 如果要 嚴格保留長寬比,可以先 pad 到正方形,再 Resize

  4. 若希望網絡天然支持 任意尺寸,可使用全卷積+自適應池化(AdaptiveAvgPool2d)結構。

根據需求(偏訓練速度、保留比例還是增強多樣性),可以選擇或組合以上方案。

二、圖像分割

在語義分割任務中,模型不僅要預測每個像素的類別,還要保證輸入圖像和標簽(pixel-wise mask)在空間上嚴格對應。不同分辨率/長寬比的處理,跟分類任務類似,但要額外注意對 mask 做相同的變換。常見做法包括:


1. 固定大小的縮放+裁剪

和分類里一樣,最簡單也最常用的方式是先把圖像和對應的 mask 同時縮放(Resize)或縮放+裁剪(CenterCrop/RandomCrop)到固定尺寸。

import torchvision.transforms.functional as Fdef train_transform(image, mask):# 假設我們要最終得到 512×512 的輸入# 1) 將短邊 resize 到 512,保留長寬比image = F.resize(image, size=512, interpolation=Image.BILINEAR)mask  = F.resize(mask,  size=512, interpolation=Image.NEAREST)# 2) 從中心或隨機裁剪出 512×512i, j, h, w = transforms.RandomCrop.get_params(image, (512, 512))image = F.crop(image, i, j, h, w)mask  = F.crop(mask,  i, j, h, w)# 3) 轉 tensor + 標準化image = F.to_tensor(image)image = F.normalize(image, mean, std)mask  = torch.as_tensor(np.array(mask), dtype=torch.long)return image, mask

優點:實現簡單、能批量訓練。
缺點:裁剪可能丟掉部分對象;大目標/小目標比例失真。


2. 保持長寬比的填充(Pad)

如果想嚴格保留原圖的長寬比,可以先對圖像和掩碼的長和寬中較大值縮放到目標size,然后再將長或寬中較小的一側padding到一個目標的長寬size,下面給出一種「先縮放長/寬中較大的一邊到目標尺寸,再對另一邊做等比填充」的實現。這樣在縮放階段處理的像素更少,最后再補齊到固定大小,計算量更低。

from PIL import Image, ImageOps
import mathdef resize_then_pad(image: Image.Image,mask: Image.Image,target_size: int = 512,pad_value_img: int = 0,pad_value_mask: int = 255):"""1) 將 image 和 mask 的長寬中較大的一邊縮放到 target_size,保持長寬比2) 對另一邊做對稱 pad,使得最終尺寸為 target_size×target_sizemask 推薦用一個不會和類別沖突的填充值(如 255)表示 padding 區域,然后在 loss 里忽略這些像素。"""w, h = image.size# 計算縮放比例scale = target_size / max(w, h)new_w, new_h = math.floor(w * scale), math.floor(h * scale)# 首先縮放image = image.resize((new_w, new_h), Image.BILINEAR)mask  = mask.resize((new_w, new_h),  Image.NEAREST)# 計算需要 pad 的像素數pad_w = target_size - new_wpad_h = target_size - new_hpad_left   = pad_w // 2pad_right  = pad_w - pad_leftpad_top    = pad_h // 2pad_bottom = pad_h - pad_top# 對稱 paddingimage = ImageOps.expand(image,border=(pad_left, pad_top, pad_right, pad_bottom),fill=pad_value_img)mask = ImageOps.expand(mask,border=(pad_left, pad_top, pad_right, pad_bottom),fill=pad_value_mask)return image, mask

用法示例

from torchvision import transforms
import torchvision.transforms.functional as Fdef train_transform(img, msk):# 1. 先 resize + padimg, msk = resize_then_pad(img, msk, target_size=512)# 2. 隨機水平翻轉等增強if random.random() > 0.5:img = F.hflip(img)msk = F.hflip(msk)# 3. 轉 Tensor,并標準化img = F.to_tensor(img)img = F.normalize(img, mean, std)msk = torch.as_tensor(np.array(msk), dtype=torch.long)return img, msk
  • 優點

    • 縮放操作只針對最大邊,像素量更少;

    • 填充操作只在小邊上,不會引入太大額外計算;

    • 保持了原始長寬比,填充區域可在損失中忽略(填充值255)。

  • 注意:pad_value_mask 選一個不會沖突的類別 id,并在 loss 里用 ignore_index=pad_value_mask

原因:很多網絡(如 U-Net、DeepLab 等)在下采樣/上采樣時要求輸入尺寸能被 2^N 整除,否則拼接或上采樣對齊會出錯。
優點:無失真;只在邊緣 padding。
缺點:padding 區域對模型無意義,可能需要在損失中忽略這些像素。

只需要在定義損失函數的時候,告訴它把填充值(pad_value_mask)對應的像素跳過即可。以下是一個最常見的做法,假設你把 padding 區域在 mask 中標記為 255,那么可以這樣寫:

import torch
import torch.nn as nn
import torch.nn.functional as F# 假設 pad_value_mask = 255
pad_value_mask = 255
num_classes = 21  # 舉例:語義分割一共 0~20 類# 定義損失函數,ignore_index 會自動忽略 mask 中等于 255 的位置
criterion = nn.CrossEntropyLoss(ignore_index=pad_value_mask)# 假設 model 輸出 logits 大小是 [B, C, H, W],mask 是 LongTensor [B, H, W]
logits = model(images)            # [B, C, H, W]
loss = criterion(logits, masks)   # masks 中值為 255 的像素不參與計算
loss.backward()

如果你更喜歡函數式的寫法,也可以用 F.cross_entropy

loss = F.cross_entropy(logits, masks, ignore_index=pad_value_mask
)

原理說明

  • CrossEntropyLoss(以及底層的 F.cross_entropy)接收一個 ignore_index 參數,所有目標標簽等于這個值的像素都會被跳過,不計入損失,也不會參與梯度更新。

  • 通常我們在 padding mask 時,選一個超出真實類別范圍的整數(比如 255),以保證不會和真實標簽沖突。

  • DataLoader 里,把 mask 轉成 torch.long,padding 時用同樣的填充值:

    # pad_value_mask = 255
    mask = ImageOps.expand(mask, border, fill=pad_value_mask)
    mask = torch.as_tensor(np.array(mask), dtype=torch.long)
    

這樣就能確保模型訓練時「看不見」那些 padding 區域,也不會因為它們引入噪聲。


3. 隨機裁剪成小塊(Patch-based Training)

如果原圖非常大(如 2000×1500),直接縮放到 512×512 會失去細節;更好的做法是“打補丁”——隨機從原圖上裁多個小塊(patch),訓練時每個 patch 都是固定大小:

# 假設想要 512×512 的訓練塊
i, j, h, w = transforms.RandomCrop.get_params(image, (512,512))
patch_img  = F.crop(image, i, j, h, w)
patch_mask = F.crop(mask,  i, j, h, w)
# 然后繼續 ToTensor、Normalize…

優點:保留高分辨率細節;增強了數據多樣性。
缺點:訓練時 batch 內 patch 來自不同原圖位置,可能導致上下文不完整,需要更多樣本。


4. 任意尺寸輸入+全卷積結構

許多經典分割網絡(FCN、U-Net、DeepLab)都是全卷積(no fully-connected layers)的,最末端用 nn.AdaptiveAvgPool2d 或直接上采樣到原始分辨率。這樣在推理階段就可以直接輸入任意尺寸的圖,網絡會輸出同樣 spatial 大小的分割圖:

class FCNSegmenter(nn.Module):def __init__(self, n_classes):super().__init__()self.backbone = torchvision.models.resnet34(pretrained=True)self.fc     = nn.Conv2d(512, n_classes, kernel_size=1)def forward(self, x):# x: B×3×H×Wfeat = self.backbone.conv1(x)# …一路下采樣…out  = self.fc(feat)               # B×C×h×wseg  = F.interpolate(out, size=x.shape[2:], mode='bilinear', align_corners=False)return seg                        # B×C×H×W

優點:不需要預先 resize/crop;推理時更靈活。
缺點:訓練時若 batch 中樣本尺寸差異過大,顯存占用和速度難以控制;通常仍在訓練時對圖像做上述固定大小處理。


5. Sliding-Window/Tiling 推理

對于超大輸入(比如遙感影像或醫學切片),即使網絡結構支持任意大小,也會因為內存限制或上下文窗口有限而采用“滑窗”(sliding window)推理:

  1. 將大圖按一定步長分塊(patch),

  2. 對每塊做分割預測,

  3. 將 patch 輸出拼接回全圖,并對重疊區域取平均或最大概率。

常見工具:

  • MMsegmentation 中的 inference_sliding

  • TorchVision 中的 SlidingWindowInferer


小結建議

  • 訓練:絕大多數場景還是先把圖和 mask 同步變換到固定大小(如 512×512),或 patch-based 隨機裁剪。

  • 推理:若輸入大小可變且不大,用全卷積網絡直接預測;若圖像過大,則用滑窗策略。

  • 注意點:所有幾何變換(resize、crop、flip、pad)都要對 image 和 mask 一致地做,而且 mask 要用最近鄰插值(interpolation=Image.NEAREST)以保證類別標簽不被混疊。

這樣,既能保證批量訓練的穩定性和效率,也能在推理時靈活應對各種分辨率和長寬比。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/92230.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/92230.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/92230.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

pytest-log

問題1:我們在運行測試用例的時候如何記錄測試的log,如何使用?問題2:我寫的函數,為了方便log記錄,但是在pytest運行時,會兼容pytest且不會重復記錄,怎么解決?1、pytest有內…

在安卓源碼中添加自定義jar包給源碼中某些模塊使用

一、具體步驟 1. 準備目錄與 Jar 包 在vendor下 創建新的模塊目錄,放入demo.jar 包: demojar/ # 模塊目錄 ├── Android.bp # 編譯配置文件 └── demo.jar 2. 編寫 Android.bp 配置 Android.bp 示例配置: java_import {…

buntu 22.04 上離線安裝Docker 25.0.5(二)

以下有免費的4090云主機提供ubuntu22.04系統的其他入門實踐操作 地址:星宇科技 | GPU服務器 高性能云主機 云服務器-登錄 相關兌換碼星宇社區---4090算力卡免費體驗、共享開發社區-CSDN博客 兌換碼要是過期了,可以私信我獲取最新兌換碼!&a…

初探 Web 環境下的 LLM 安全:攻擊原理與風險邊界

文章目錄前言1 什么是大型語言模型(LLM)?1.1 LLM的核心特征1.2 LLM在Web場景中的典型應用2 LLM攻擊的核心手段:提示注入與權限濫用3 LLM與API集成的安全隱患:工作流中的漏洞節點3.1 LLM-API集成的典型工作流3.2 工作流…

【新手向】PyTorch常用Tensor shape變換方法

【新手向】PyTorch常用Tensor shape變換方法 前言 B站UP主科研水神大隊長的視頻中介紹了“縫合模塊”大法,其中專門強調了“深度學習 玩的就是shape”。受此啟發,專門整理能夠調整tensor形狀的幾個內置函數,方便以后更好地調整PyTorch代碼中的…

React 18 vs Vue3:狀態管理方案深度對比

?? 背景: React有Redux、Zustand、Jotai等方案 Vue有Pinia、Vuex 4.x 如何選擇適合項目的方案? ?? 核心對比: 維度 React (Redux Toolkit) Vue3 (Pinia) 類型安全 ? 需手動配置TS ? 自動類型推導 代碼量 較多(需寫action) 較少(類似Vuex 5) 響應式原理 不可變數據…

UE5網絡聯機函數

Find Sessions Create Session Join Session Destroy Session Steam是p2p直接聯機 一、steam提供的測試用AppId AppId是steam為每一款游戲所設定的獨有標識,每一款要上架steam的游戲都會擁有獨一無二的AppId。不過為了方便開發者測試,steam提供了游…

Spring Boot 監控:AOP vs Filter vs Java Agent

01前言 在 高并發 微服務 中, 傳統 手動埋點(System.currentTimeMillis())就像用體溫計量火箭速度——代碼侵入、重復勞動、維護爆炸。 下文是無侵入、高精度、全鏈路 監控 API 耗時,全程不碰業務代碼的方案! 02實戰&…

基于Android的電子記賬本系統

博主介紹:java高級開發,從事互聯網行業多年,熟悉各種主流語言,精通java、python、php、爬蟲、web開發,已經做了多年的畢業設計程序開發,開發過上千套畢業設計程序,沒有什么華麗的語言&#xff0…

7月17日日記

結束了數學建模之后的這兩天一直在緊張的復習,但是說實話效率有點低,因為可能覺得自己找到了兩個小時速成課,覺得無所謂了,所以有點放松了。在宿舍杰哥和林雨城卻一直在復習,感覺他們的微積分和線性代數復習的都比我好…

Linux下SPI設備驅動開發

一.SPI協議介紹1.硬件連接介紹引腳含義:DO(MOSI):Master Output, Slave Input,SPI主控用來發出數據,SPI從設備用來接收數據。DI(MISO):Master Input, Slave Output,SPI主控用來發出數據,SPI從設…

用Dify構建氣象智能體:從0到1搭建AI工作流實戰指南

作為一名Agent產品經理,我最近在負責氣象智能體的建設項目。傳統氣象服務面臨三大痛點:數據孤島嚴重(氣象局API、衛星云圖、地面觀測站等多源數據格式不一)、響應鏈路長(從數據采集到預警發布需人工介入多個環節)、交互體驗單一(用戶只能被動接收標準化預警,無法個性化…

Android NDK ffmpeg 音視頻開發實戰

文章目錄接入FFmpeg1.下載FFmpeg 源碼2.編譯FFmpeg.so庫異常處理3.自定義FFmpeg交互so庫創建4.配置CMakeLists.txt5.CMakeLists.txt 環境配置6.Native與Java層調用解碼器準備接入FFmpeg 1.下載FFmpeg 源碼 FFmpeg官網地址 2.編譯FFmpeg.so庫 移動 FFmpeg 源碼文件夾至 Andr…

使用 go-redis-entraid 實現 Entra ID 無密鑰認證

1、依賴與安裝 步驟命令說明安裝(或升級) go-redis v9.9go get github.com/redis/go-redis/v9latestentraid 必須 ≥ 9.9.0安裝 go-redis-entraidgo get github.com/redis/go-redis-entraid自動拉取 transit 依賴 2、認證方式一覽 方式說明創建 Stream…

window上docker安裝RabbitMQ

1、要進http://localhost:15672管理頁面需要安裝management版本2、搜索鏡像并pull3、啟動鏡像時將端口映射出來4、啟動成功,點擊可查看日志詳情,瀏覽器訪問5、直接使用guest/guest登錄會報錯User can only log in via localhost解決辦法有兩個&#xff1…

異世界歷險之數據結構世界(排序(插入,希爾,堆排))

前言 介紹 插入排序 基本知識: 直接插入排序是一種簡單的插入排序法,其基本思想是: 把待排序的記錄按其關鍵碼值的大小逐個插入到一個已經排好序的有序序列中,直到所有的記錄插入完為止,得到一個新的有序序列 直接插入…

oracle 數據庫中,將幾張表的數據按指定日期范圍實時同步至同一個數據庫的備份表中。

以下是一個Oracle數據庫中實現表數據按指定日期范圍實時同步至備份表的解決方案。這個方案使用存儲過程和觸發器組合實現: 1. 創建備份表結構 首先需要為每張需要備份的表創建對應的備份表,結構與原表相同: -- 為原表創建備份表(示…

電腦網絡連接正常,微信、QQ能正常使用,但無法訪問網頁?DNS問題的解決方案和背后原理。

文章目錄1. 問題背景2. 解決方案2.1 手動刷新DNS2.1.1 Windows版本2.1.2 Mac版本2.2 手動設置DNS服務器2.2.1 Windows版2.2.2 Mac版2.3 其他解決方案3. DNS是什么?3.1 詳細解釋DNS3.1.1 A distributed, hierarchical database(一個分布式和分層數據庫結構…

【HTML】圖片比例和外部div比例不一致,最大程度占滿

圖片比例和外部div比例不一致&#xff0c;最大程度占滿&#xff0c;并且圖片比例不變 其中1.jpg,2.jpg,1.html在同一目錄 |-----|- 1.jpg|- 2.jpg|- 1.html1.jpg2.jpg<!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /&g…

如何使用python網絡爬蟲批量獲取公共資源數據技術

如何快速批量地獲取海量公共資源數據決定了科研的效率。Python網絡爬蟲是快速批量獲取網絡數據的重要手段&#xff0c;它按照發送請求、獲得頁面、解析頁面、下載內容、儲存內容等流程&#xff1f; 一&#xff1a;Python軟件的安裝及入門1 Python軟件安裝及入門1)Anaconda軟件安…