【IQA技術專題】DISTS代碼講解

本文是對DISTS圖像質量評價指標的代碼解讀,原文解讀請看DISTS文章講解。
本文的代碼來源于IQA-Pytorch工程。

1、原文概要

以前的一些IQA方法對于捕捉紋理上的感知一致性有所欠缺,魯棒性不足。基于此,作者開發了一個能夠在圖像結構和圖像紋理上都具有與人類相同感知判斷的指標,在此之上,還希望紋理能夠resample(不需要像素級對齊)之后也是一樣的,另外區分開退化(JPEG,JPEG會損失紋理)。實現該指標可以分為4個步驟:

  1. 對圖像進行一個初始的變換,從像素空間變換到特征空間。
  2. 對特征提取所謂紋理的表示,對特征提取所謂結構的表示。
  3. 利用紋理和結構的表示,加入一些可學習的權重綜合計算一個評價指標。
  4. 利用這個評價指標,進一步優化權重得到紋理區域resample不敏感的指標,且能夠有結構和紋理上做感知相似度的模型。

實現后的指標作為優化指標對比其他IQA指標有明顯優勢,如下圖所示。
在這里插入圖片描述

2、代碼結構

代碼實現位于pyiqa/archs/dists_arch.py中
在這里插入圖片描述

3 、核心代碼模塊

L2pooling

這個類實現了我們前面提到的預處理部分替換max-pool的操作。

class L2pooling(nn.Module):def __init__(self, filter_size=5, stride=2, channels=None, pad_off=0):super(L2pooling, self).__init__()self.padding = (filter_size - 2) // 2self.stride = strideself.channels = channelsa = np.hanning(filter_size)[1:-1]g = torch.Tensor(a[:, None] * a[None, :])g = g / torch.sum(g)self.register_buffer('filter', g[None, None, :, :].repeat((self.channels, 1, 1, 1)))def forward(self, input):input = input**2out = F.conv2d(input,self.filter,stride=self.stride,padding=self.padding,groups=input.shape[1],)return (out + 1e-12).sqrt()

這里可以看到前向的過程中作者先是進行了一個平方,然后使用了一個self.filter的濾波器,kernel_size為3的hanning窗,stride=2,且是一個深度可分離的卷積,groups與輸入通道一致,這代替max-pool完成了一次抗混疊的下采樣,最后進行一個sqrt,這與講解中展示的公式一致,如下所示:
P(x)=g?(x?x)P(x)=\sqrt{g*(x*x)}P(x)=g?(x?x)?這個ggg在初始化時被復制了self.channels次,實際它一個通道的數值,讀者可以打印如下所示:
[0.06250.1250.06250.1250.250.1250.06250.1250.0625]\begin{bmatrix} 0.0625 & 0.125 & 0.0625 \\ 0.125 & 0.25 & 0.125 \\ 0.0625 & 0.125 & 0.0625 \end{bmatrix} ?0.06250.1250.0625?0.1250.250.125?0.06250.1250.0625??一個典型的低通濾波器,做了一個空間上根據距離的平均。

DISTS

存放著跟實際計算指標相關的代碼。

@ARCH_REGISTRY.register()
class DISTS(torch.nn.Module):r"""DISTS model.Args:pretrained_model_path (String): Pretrained model path."""def __init__(self, pretrained=True, pretrained_model_path=None, **kwargs):"""Refer to official code https://github.com/dingkeyan93/DISTS"""super(DISTS, self).__init__()vgg_pretrained_features = models.vgg16(weights='IMAGENET1K_V1').featuresself.stage1 = torch.nn.Sequential()self.stage2 = torch.nn.Sequential()self.stage3 = torch.nn.Sequential()self.stage4 = torch.nn.Sequential()self.stage5 = torch.nn.Sequential()for x in range(0, 4):self.stage1.add_module(str(x), vgg_pretrained_features[x])self.stage2.add_module(str(4), L2pooling(channels=64))for x in range(5, 9):self.stage2.add_module(str(x), vgg_pretrained_features[x])self.stage3.add_module(str(9), L2pooling(channels=128))for x in range(10, 16):self.stage3.add_module(str(x), vgg_pretrained_features[x])self.stage4.add_module(str(16), L2pooling(channels=256))for x in range(17, 23):self.stage4.add_module(str(x), vgg_pretrained_features[x])self.stage5.add_module(str(23), L2pooling(channels=512))for x in range(24, 30):self.stage5.add_module(str(x), vgg_pretrained_features[x])for param in self.parameters():param.requires_grad = Falseself.register_buffer('mean', torch.tensor([0.485, 0.456, 0.406]).view(1, -1, 1, 1))self.register_buffer('std', torch.tensor([0.229, 0.224, 0.225]).view(1, -1, 1, 1))self.chns = [3, 64, 128, 256, 512, 512]self.register_parameter('alpha', nn.Parameter(torch.randn(1, sum(self.chns), 1, 1)))self.register_parameter('beta', nn.Parameter(torch.randn(1, sum(self.chns), 1, 1)))self.alpha.data.normal_(0.1, 0.01)self.beta.data.normal_(0.1, 0.01)if pretrained_model_path is not None:load_pretrained_network(self, pretrained_model_path, False)elif pretrained:load_pretrained_network(self, default_model_urls['url'], False)def forward_once(self, x):h = (x - self.mean) / self.stdh = self.stage1(h)h_relu1_2 = hh = self.stage2(h)h_relu2_2 = hh = self.stage3(h)h_relu3_3 = hh = self.stage4(h)h_relu4_3 = hh = self.stage5(h)h_relu5_3 = hreturn [x, h_relu1_2, h_relu2_2, h_relu3_3, h_relu4_3, h_relu5_3]def forward(self, x, y):r"""Compute IQA using DISTS model.Args:- x: An input tensor with (N, C, H, W) shape. RGB channel order for colour images.- y: An reference tensor with (N, C, H, W) shape. RGB channel order for colour images.Returns:Value of DISTS model."""feats0 = self.forward_once(x)feats1 = self.forward_once(y)dist1 = 0dist2 = 0c1 = 1e-6c2 = 1e-6w_sum = self.alpha.sum() + self.beta.sum()alpha = torch.split(self.alpha / w_sum, self.chns, dim=1)beta = torch.split(self.beta / w_sum, self.chns, dim=1)for k in range(len(self.chns)):x_mean = feats0[k].mean([2, 3], keepdim=True)y_mean = feats1[k].mean([2, 3], keepdim=True)S1 = (2 * x_mean * y_mean + c1) / (x_mean**2 + y_mean**2 + c1)dist1 = dist1 + (alpha[k] * S1).sum(1, keepdim=True)x_var = ((feats0[k] - x_mean) ** 2).mean([2, 3], keepdim=True)y_var = ((feats1[k] - y_mean) ** 2).mean([2, 3], keepdim=True)xy_cov = (feats0[k] * feats1[k]).mean([2, 3], keepdim=True) - x_mean * y_meanS2 = (2 * xy_cov + c2) / (x_var + y_var + c2)dist2 = dist2 + (beta[k] * S2).sum(1, keepdim=True)score = 1 - (dist1 + dist2)return score.squeeze(-1).squeeze(-1)

3個重點如下:

  1. 初始化中首先會插入前面講到的L2_Pooling,來替換原始的max-pool,其他的就是初始化必要的標準化變量和用于各層結構和紋理的加權系數α\alphaαβ\betaβ,最后導入預訓練的網絡即可。
  2. 前向中調用的forward_once,可以看到總共有6個輸出,第一個輸出是輸入x,即我們講解中提到的identity的變換,其他5層是事先定義好的輸出位置。
  3. dists的計算:首先根據權重的大小對alpha和beta進行歸一化,隨后分層計算我們前面定義好的紋理特征和結構特征的相關性公式,針對于紋理的部分代碼中是S1,可以看到S1是利用了特征的在空間上的均值計算的參考圖像和待評估圖像的相關系數,然后利用alpha對計算好的S1進行加權,得到紋理上相似度dist1;針對于結構的部分代碼中是S2,S2是利用了參考圖像和待評估圖像兩個特征的協方差和方差,由于是全局的窗口所以在計算后會求取空間上的一個均值,這樣得到了結構上的相似度dist2。最后結合dist1和dist2得到最終的score。dists計算的公式如下,可以對照著公式來查看:
    l(x~j(i),y~j(i))=2μx~j(i)μy~j(i)+c1(μx~j(i))2+(μy~j(i))2+c1l(\tilde{x}_j^{(i)}, \tilde{y}_j^{(i)}) = \frac{2\mu_{\tilde{x}_j}^{(i)}\mu_{\tilde{y}_j}^{(i)} + c_1}{(\mu_{\tilde{x}_j}^{(i)})^2 + (\mu_{\tilde{y}_j}^{(i)})^2 + c_1}l(x~j(i)?,y~?j(i)?)=(μx~j?(i)?)2+(μy~?j?(i)?)2+c1?2μx~j?(i)?μy~?j?(i)?+c1?? s(x~j(i),y~j(i))=2σx~jy~j(i)+c2(σx~j(i))2+(σy~j(i))2+c2,s(\tilde{x}_j^{(i)}, \tilde{y}_j^{(i)}) = \frac{2\sigma_{\tilde{x}_j\tilde{y}_j}^{(i)} + c_2}{(\sigma_{\tilde{x}_j}^{(i)})^2 + (\sigma_{\tilde{y}_j}^{(i)})^2 + c_2},s(x~j(i)?,y~?j(i)?)=(σx~j?(i)?)2+(σy~?j?(i)?)2+c2?2σx~j?y~?j?(i)?+c2??, D(x,y;α,β)=1?∑i=0m∑j=1ni(αijl(x~j(i),y~j(i))+βijs(x~j(i),y~j(i)))D(x, y; \alpha, \beta) = 1 - \sum_{i = 0}^{m} \sum_{j = 1}^{n_i} \left( \alpha_{ij} l(\tilde{x}_j^{(i)}, \tilde{y}_j^{(i)}) + \beta_{ij} s(\tilde{x}_j^{(i)}, \tilde{y}_j^{(i)}) \right)D(x,y;α,β)=1?i=0m?j=1ni??(αij?l(x~j(i)?,y~?j(i)?)+βij?s(x~j(i)?,y~?j(i)?))其中,lllsss分別代表紋理和結構。

3、總結

代碼實現核心的部分講解完畢,DISTS作為一個可以同時捕獲結構和紋理相似度的全參考IQA指標,在很多比賽和論文的引用中都可以見到它的身影,實用性是毋庸置疑的。
大家有涉及到數據集篩選、紋理分類、紋理搜索類的任務可以嘗試使用DISTS指標,或者是在算法評估中利用它來做一個方面的對比評估。


感謝閱讀,歡迎留言或私信,一起探討和交流。
如果對你有幫助的話,也希望可以給博主點一個關注,感謝。

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

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

相關文章

2024年SEVC SCI2區,一致性虛擬領航者跟蹤群集算法GDRRT*-PSO+多無人機路徑規劃,深度解析+性能實測

目錄1.摘要2.算法背景3.GDRRT*-PSO與虛擬領航者跟蹤算法4.結果展示5.參考文獻6.算法輔導應用定制讀者交流1.摘要 隨著無人機技術的快速發展及其卓越的運動和機動性能,無人機在社會和軍事等諸多領域得到了廣泛應用。多無人機協同作業,能夠顯著提升任務執…

鏈特異性文庫是什么?為什么它在轉錄組測序中越來越重要?

鏈特異性文庫是什么?為什么它在轉錄組測序中越來越重要? 在現代分子生物學研究中,RNA測序(RNA-seq) 是一種廣泛應用的技術,用于分析基因在不同條件下的表達情況。而在RNA-seq的眾多技術細節中,有…

ClickHouse vs PostgreSQL:數據分析領域的王者之爭,誰更勝一籌?

文章概要 作為一名數據架構師,我經常被問到一個問題:在眾多數據庫選擇中,ClickHouse和PostgreSQL哪一個更適合我的項目?本文將深入探討這兩種數據庫系統的核心差異、性能對比、適用場景以及各自的優缺點,幫助您在技術選…

面向對象系統的單元測試層次

面向對象系統的單元測試層次面向對象(Object-Oriented, OO)編程范式引入了封裝、繼承和多態等核心概念,這使得傳統的、基于函數的單元測試方法不再充分。面向對象系統的單元測試必須適應其獨特的結構和行為特性,從單一方法擴展到類…

如何用USRP捕獲手機信號波形(上)系統及知識準備

目錄: 如何用USRP捕獲手機信號波形(上)系統及知識準備 如何用USRP捕獲手機信號波形(中)手機/基站通信 如何用USRP捕獲手機信號波形(下)協議分析 一、手機通信參數獲取 首先用Cellular-z網絡…

C語言-數組:數組(定義、初始化、元素的訪問、遍歷)內存和內存地址、數組的查找算法和排序算法;

本章概述思維導圖:C語言數組在C語言中,數組是一種固定大小的、相同類型元素的有序集合,通過索引(下標)訪問。數組數組:是一種容器,可以用來存儲同種數據類型的多個值;數組特點&#…

河南萌新聯賽2025第(二)場:河南農業大學(補題)

文章目錄前言A.約數個數和整除分塊(相當于約數求和)相關例題:取模B.異或期望的秘密二進制的規律相關例題累加器小藍的二進制詢問乘法逆元1. 概念2.基本定義3.費馬小定理1.定理內容2.重要推論D.開羅爾網絡的備用連接方案E.咕咕嘎嘎!!!(easy)I.猜數游戲(easy)K.打瓦M.…

常見中間件漏洞

一、TomcatTomcat put方法任意文件寫入漏洞環境搭建,啟動時端口被占用就改yml配置文件,改成8081端口。(我這里是8080)cd vulhub-master/tomcat/CVE-2017-12615 docker-compose up -d 去抓包,改成put提交。下面的內容是用哥斯拉生成的木馬文件…

27.(vue3.x+vite)以pinia為中心的開發模板(監聽watch)

效果截圖 代碼實現: HelloWorld.vue <template><div style="padding: 20px">介紹:<br />1:使用統一的 watch 來監聽store的值。<br

Jenkins 詳解

Jenkins 是一個開源的持續集成和持續交付(CI/CD)工具&#xff0c;用于自動化軟件開發過程中的構建、測試和部署階段。以下是關于 Jenkins 的詳細介紹&#xff1a; 1. Jenkins 核心概念 1.1 持續集成(CI) 開發人員頻繁地將代碼變更提交到共享倉庫每次提交都會觸發自動構建和測試…

動態配置實現過程

查看DCCValueBeanFactory類的完整實現&#xff0c;了解動態配置的實現過程 動態配置實現過程 1. 自定義注解 使用DCCValue注解標記需要動態配置的字段&#xff0c;格式為key:defaultValue&#xff1a; DCCValue("downgradeSwitch:0") private String downgradeSw…

【大模型理論篇】跨語言AdaCOT

參考&#xff1a;AdaCoT: Rethinking Cross-Lingual Factual Reasoning throughAdaptive Chain-of-ThoughtAdaCoT&#xff08;Adaptive Chain-of-Thought&#xff0c;自適應思維鏈&#xff09;是一項提升大型語言模型&#xff08;LLMs&#xff09;跨語言事實推理能力的新框架。…

vue3項目搭建

前一段時間招聘前端開發,發現好多開發連基本的創建項目都不會,這里總結一下 在Vue 3中,使用Webpack和Vite創建的項目文件結構及語言(JS/TS)的選擇有以下主要區別: 1. 創建方式與文件結構差異 方式一、Webpack(Vue CLI) 創建命令: vue create project-name 典型文件結構…

企業簽名的多種形式

企業簽名有多種形式&#xff0c;可分為企業簽名獨立版、企業簽名穩定版、企業簽名共享版等。每一種形式的企業簽名都有其獨特的特點&#xff0c;其中&#xff1a;  企業簽名獨立版&#xff1a;其特性主要為穩定性較高&#xff0c;使用者可以通過控制APP的下載量來保證APP的穩…

解構遠程智能系統的視頻能力鏈:從RTSP|RTMP協議接入到Unity3D頭顯呈現全流程指南

在人工智能奔騰的2025年&#xff0c;WAIC&#xff08;世界人工智能大會&#xff09;釋放出一個明確信號&#xff1a;視頻能力已經成為通往“遠程智能”的神經中樞。在無人機、四足機器人、遠程施工、巡檢等新興場景中&#xff0c;一套可靠、低延遲、可嵌入頭顯設備的視頻傳輸系…

Less Less基礎

1.lessless是一種動態樣式語言&#xff0c;屬于CSS預處理器的范疇&#xff0c;它擴展了CSS語言&#xff0c;增加了變量&#xff0c;Mixin&#xff0c;函數等特性&#xff0c;使CSS更易維護和擴展。Less既可以在客戶端上運行&#xff0c;也可以借助Node.js在服務端運行。2.Less中…

如何使用 Redis 實現 API 網關或單個服務的請求限流?

使用 Redis 高效實現 API 網關與服務的請求限流 在微服務架構中&#xff0c;對 API 網關或單個服務的請求進行速率限制至關重要&#xff0c;以防止惡意攻擊、資源濫用并確保系統的穩定性和可用性。 Redis 憑借其高性能、原子操作和豐富的數據結構&#xff0c;成為實現請求限流的…

圖片查重從設計到實現(7) :使用 Milvus 實現高效圖片查重功能

使用 Milvus 實現高效圖片查重功能本文將介紹如何利用 Milvus 向量數據庫構建一個高效的圖片查重系統&#xff0c;通過傳入圖片就能快速從已有數據中找出匹配度高的相似圖片。一.什么是圖片查重&#xff1f; 圖片查重指的是通過算法識別出內容相同或高度相似的圖片&#xff0c;…

誘導多能干細胞(iPSC)的自述

自十七年前誘導多能干細胞&#xff08;也稱iPS細胞或iPSC&#xff09;技術出現以來&#xff0c;干細胞生物學和再生醫學取得了巨大進展。人類iPSC已廣泛用于疾病建模、藥物發現和細胞療法開發。新的病理機制已被闡明&#xff0c;源自iPSC篩選的新藥正在研發中&#xff0c;并且首…

基于深度學習的醫學圖像分析:使用DeepLabv3+實現醫學圖像分割

前言 醫學圖像分析是計算機視覺領域中的一個重要應用&#xff0c;特別是在醫學圖像分割任務中&#xff0c;深度學習技術已經取得了顯著的進展。醫學圖像分割是指從醫學圖像中識別和分割出特定的組織或器官&#xff0c;這對于疾病的診斷和治療具有重要意義。近年來&#xff0c;D…