德國萊比錫訂購首批純電池動力列車,2023 年開始營運

法國運輸公司阿爾斯通(Alstom)日前宣布,正式簽下一筆價值 1 億歐元(約新台幣 32 億元) 的訂單,將在兩年內於德國部署 11 輛電池動力列車,並負責其後續服務直到 2032 年。

Alstom 的列車產品幾乎無所不包,而針對中程區間車款推出的 Coradia 系列已經有 30 年歷史,在 2018 年底,他們推出的氫燃料電池列車 Coradia iLint 營運至今成效良好,並陸續在其他地區接獲訂單,而這次他們將打造的新列車將是純電池動力型態。

這筆訂單的服務目標,是要連接德國東部大城萊比錫與開姆尼茨之間,距離約 80 公里的路線,這一段鐵路並沒有電氣化,目前只能使用柴油列車,為了省下電氣化的工程與費用,當地的鐵路業者決定採購電池動力列車,而且 2023 年就能上路。

這款新列車將命名為 Coradia Continental BEMU,完全依靠電池動力運行,里程可達 120 公里,並且能夠在電氣化或非電氣化鐵道行駛。列車由三節車廂組成,長度約 56 公尺,共有 150 個座位。

電動列車最快的行駛速度可達每小時 160 公里,阿爾斯通沒有提供詳細的電池規格,只表示將採用高壓鋰離子電池組,並且依據運營路線的距離去最佳化列車行駛的速度。

目前阿爾斯通在德國的新能源列車已經有兩家客戶,總共採購了 41 輛氫燃料電池列車,在德國聯邦政府全力拼減碳的目標下,這些零排放列車都能獲得約 40% 的補助。

台灣鐵路幾乎都已經電氣化,目前只剩下南迴鐵路總計 123.4 公里尚未完成,目前行政院已經核定經費 276 億施工,工程時間長達 9 年,預定於 2020 年底能全線完工。如果對比阿爾斯通的電池列車方案,確實可以省下大筆經費與時間,不過電氣化完工後,原本在東部幹線運行的臺鐵普悠瑪也能夠使用,而且不用擔心電池充電問題與壽命衰退的可能,只能說優劣各半。

但許多國家不像台灣有這麼完整的電氣化鐵路網,因此未來逐步淘汰柴油列車時,這種電池動力列車與氫燃料電池列車的商機,仍然非常可觀。

(合作媒體:。首圖來源:)

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

※廣告預算用在刀口上,網站設計公司幫您達到更多曝光效益

※自行創業 缺乏曝光? 下一步"網站設計"幫您第一時間規劃公司的門面形象

南投搬家前需注意的眉眉角角,別等搬了再說!

go語言教程之淺談數組和切片的異同

Hello ,各位小夥伴大家好,我是小棧君,上次分享我們講到了Go語言關於項目工程結構的管理,本期的分享我們來講解一下關於go語言的數組和切片的概念、用法和區別。

在go語言的程序開發過程中,我們避免不了數組和切片。關於他們的用法和區別卻使得有的小夥伴感覺困惑。所以小棧君這裏也歸納和總結了關於數組和切片的乾貨幫助小夥伴進行理解。

數組的定義

數組是具有相同唯一類型的一組已編號且長度固定的數據項序列,這種類型可以是任意的原始類型例如整形、字符串或者自定義類型。

相對於去聲明 number0, number1, …, number99 的變量,使用數組形式 numbers[0], numbers[1] …, numbers[99] 更加方便且易於擴展。

數組元素可以通過索引(位置)來讀取(或者修改),索引從 0 開始,第一個元素索引為 0,第二個索引為 1,以此類推。

總體來講的話數組就是同一種類型的固定長度的序列。

在go語言中數組的定義是很簡單的。

如圖所示,我們定義了一個長度為2的數組,在數組定義的過程中,系統已經對這個數組進行了初始化並分配了空間。所以我們如果想要進行賦值可以通過數組名加上下標的方式進行賦值。但是值得注意的一點是我們並不能進行數組的超長處理。這一點有別於java的數組定義,java的定長數組添加值后如果對於超出的值會有自動擴容功能。

但是在go語言中並沒有方法來進行增刪改查值,只有通過下標的方式,所以我們如果進行了越界處理編譯都會進行報錯。所以才入門的小夥伴們需要注意一下哦。數組的下標在數組的合法範圍之外就會出發訪問越界,會有panic出現。所以小棧君也是通過了一個實例給大家說明一下,因為編譯可能會不通過,所以我們巧妙的避開編譯器的編譯進行數組的越界操作說明。

當然需要值得注意的一點是,數組的長度也是數組類型的一部分,因此var a [2]int 和 var b [3] int 是兩個不同的類型。

知識點來了,在go語言中的數組是屬於值類型傳遞,當我們傳遞一個數組到一個方法中,改變副本的值並不會修改到原本數組的值。所以得到的數組還是原來的樣子。

因此如果我們要對數組進行值的修改的話,就只有進行指針操作啦~。

切片的概念

在go語言中數組中長度不可以更改,所以在實際的應用環境中並不是非常實用,所以Go語言衍生出了一種靈活性強和功能更強大的內置類型,即為切片。

與上面所講的數組相比,切片的長度是不固定的,並且切片是可以進行擴容。切片對象非常小,是因為它是只有3個字段的數據結構:一個是指向底層數組的指針,一個是切片的長度,一個是切片的容量。這3個字段,就是Go語言操作底層數組的元數據,有了它們,我們就可以任意的操作切片了。

當然,切片作為數組的引用,所以切片屬於是引用類型,各位小夥伴可千萬要記住了哦。在切片的使用過程當中,我們可以通過遍曆數組的方式進行對於切片的遍歷,我們也可以內置方法len對數組或切片進行長度的計算。

當然我們也可以對切片的容量進行計算,之前有講過Go語言有豐富的內置庫提供給我們使用,所以我們也可以cap內置函數進行容量的計算。多個切片如果表示同一個數組的片段,它們可以共享數據;因此一個切片和相關數組的其他切片是共享存儲的,相反,不同的數組總是代表不同的存儲。數組實際上是切片的構建塊。

上面的例子小棧君分別用數組和切片進行了測試,我們可以看到數組的容量一旦確定后就無法進行更改,當我們的切片進行初始化,初始的容量是2,此時切片的容量和長度都是2,但是我通過內置的append方法進行了切片的增加。此時的切片的容量和長度都是4。此時我們並不能確定切片內置擴容的機制,但是隱約猜測是倍增。

言歸正傳,為了測試一下切片的擴容機制,所以小棧君又進行了切片的增加,此時,細心的小夥伴應該發現,這次小棧君一次性增加了兩個元素在一個append裏面,因為這是append方法是一個可變長度的傳值。這也是一個小知識點哦。

如果切片的底層數組,沒有足夠的容量時,就會新建一個底層數組,把原來數組的值複製到新底層數組裡,再追加新值,這時候就不會影響原來的底層數組了。

append目前的算法是:容量小於1000個時,總是成倍的增長,一旦容量超過1000個,增長因子設為1.25,也就是說每次會增加25%的容量。

之後我們發現切片的容量和長度發生了變化,如果說上次容量的擴張是4是我們猜測的倍數擴容方式,那麼這次我們就實錘了他的擴容機制就是倍增。而且在Go語言的容量和長度不一樣,所以我們也可以得出結論,就是在 0 <= len(arry) <= cap(slice)。

在我們聲明好切片后我們可以使用new或是make方法對切片進行初始化,當然小棧君也試着嘗試證明切片如果沒有進行初始化是會panic的。結果並沒有出現。因為如果slice沒有初始化,它僅僅相當於一個nil,長度和容量都為0,並不會panic。

小棧君也考慮到可能是因為沒有內置增加方法或是沒有報錯僅僅只是因為我後面利用對Carry數組的切割進行賦值的緣故。所以不甘心又做了一次嘗試,定義好相應的切片后直接使用append方法,結果如下:

我們同樣可以通過上述的例子了解到切片的下標是左閉右開區間,因為我們carry數組的內容如上圖所示, 我們最終得到的結果是IT乾貨棧,下標來講的話是屬於1。所以我們得到的結論和事實是一樣的。對於切片我們也有很多用法,如下圖所示:

下圖是Python中對於切片的操作,並且Python中的數組更為靈活,在後面我為大家分享Python教程的時候會詳細分享哦。

切片的初始化

對於切片的初始化我們可以make方法和new方法

new(T) 為每個新的類型T分配一片內存,初始化為 0 並且返回類型為*T的內存地址:這種方法 返回一個指向類型為 T,值為 0 的地址的指針,它適用於值類型如數組和結構體;它相當於 &T{}。

make(T) 返回一個類型為 T 的初始值,它只適用於3種內建的引用類型:切片、map 和 channel。

拷貝

因為在go語言的數組是屬於值傳遞,之前的方法也證實了這一點,在方法傳遞值的時候系統會進行拷貝一份副本進行傳遞,如果需要改變的值的話就需要使用指針。但是在使用切片處理的時候,因為切片屬於引用傳遞,所以go語言有內置的函數copy方法進行值的拷貝。

上述的一個例子可以綜合說明幾點問題了,最開始我們定義了一個切片並且容量是2,內容是1和2,我們同樣定義了切片b但是並沒有做初始化處理。直接使用copy操作。使用copy操作的時候,小棧君也複製了源碼出來,第一個是我們的數據源,第二個參數傳遞我們的目標源。直接使用的話我們可以從結果看出並沒有成功。

所以接下來小棧君又進行了初始化操作。這裏舉例的目的是提醒各位,在操作切片的時候沒有初始化就相當於nil,最好是進行切片的初始化操作。在早期go語言的版本中,沒有初始化切片會直接報錯。接下來我又進行了再一次的複製操作並且打印出他們的地址和容量、長度。可以看出進行切片的拷貝是不會進行切片的擴容處理。而且他們分別指向了不同的地址說明拷貝成功。

好了,今天的分享就到這啦,如果你喜歡我的分享,麻煩你點擊一個好看或贊,我是小棧君,不定期分享IT乾貨,包括但不限於區塊鏈、大數據、Python、go、等系列專題。希望與你共同成長。我們下期再見啦,拜了個拜~

本文由博客一文多發平台 發布!

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】

※帶您來了解什麼是 USB CONNECTOR  ?

※自行創業 缺乏曝光? 下一步"網站設計"幫您第一時間規劃公司的門面形象

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!!

※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

※廣告預算用在刀口上,網站設計公司幫您達到更多曝光效益

基於曝光融合框架的對比度增強算法

目錄

論文題目《A New Image Contrast Enhancement Algorithm Using Exposure Fusion Framework》翻譯以及分析

摘要

低光圖像不利於人眼觀察和計算機視覺算法識別,因為它們的可見度較低。雖然已經提出了許多圖像增強技術來解決這個問題。但是現有方法不可避免地存在對比度過低和過高的情況。在本文中,我們提出了一種精確的對比度增強的算法。具體來說,我們首先使用光照估計技術為圖像融合設計權重矩陣。然後,我們用相機的響應模型合成多重曝光圖像。接下來,我們找到最佳的曝光率,為了合成圖像在原始圖像曝光不足的區域進行更好的曝光。最後,輸入圖像和合成圖像根據權重矩陣進行融合以獲得圖像增強的結果。實驗表明,相比其他優秀的方法,我們的方法可以得到對比度和亮度失真更少的結果。

1. 研究現狀

圖像增強技術廣泛用於圖像處理中。一般來說,它可以使輸入圖像看起來更好,並且更適合於特定算法進行處理。對比度增強,作為一種增強技術,可以在圖像中显示曝光不足區域的信息。目前有大量的對比度增強的技術,主要包括基於直方圖,基於Retinex和基於除霧的方法的增強技術。

彩色圖像可以用三維數組表示。最簡單的對比度增強的方法是對每個對象執行相同的處理過程。例如,最早的圖像增強方法使用非線性單調函數進行灰度級映射。

考慮到不同灰度級別中元素的不均勻分佈,因此直方圖均衡化(HE)被廣泛用於改善對比度。許多直方圖均衡化的擴展方法將亮度保存和對比度限制考慮進去。但是基於直方圖均衡化的方法總是會過度增強和產生不切實際的結果。在模仿在人類視覺系統中,Retinex理論也廣泛用於圖像增強。通過將反射圖與光照圖分開,基於Retinex的算法可以明顯增強細節。但是這些方法在高對比度區域容易產生偽像。近年來,一些方法應用除霧技術來增強對比度並獲得良好的主觀視覺效果。但是這些方法也可能會因為對比度過度增強而導致顏色失真。

儘管圖像對比度增強方法研究了幾十年,但是好的增強效果仍然沒有很好的定義。此外,現有的弱光增強算法也沒有提供參考如何定位過度增強和不足增強區域。我們注意到不同的圖像曝光度可以作為增強算法的參考,如圖1所示。隨着曝光度的增加,一些低曝光區域變得曝光良好。增強的結果應保持曝光良好的區域保持不變,而曝光不足的區域則增強。與此同時,增強區域的對比度應與正確曝光區域保持一致。

在本文中,我們提出了一個新的框架來幫助緩解欠/過度增強的問題。我們的框架基於相機響應模型從輸入圖像合成的多張曝光圖像的曝光融合。基於我們的框架,我們提出了一種增強算法與其他幾種相比最先進的方法,可以獲得更少的對比度和亮度失真的結果。

2. 本文方法

2.1 曝光融合框架

在許多室外場景中,相機無法使所有像素曝光良好,因為它的動態範圍是有限的。如圖1所示儘管我們可以通過增加曝光量显示一些曝光不足的區域,與此同時曝光良好的區域可能同時曝光過度。為了讓所有像素的圖像曝光良好,我們可以融合這些圖像:
\[ R^c = \sum\limits_{i=1}^{N}W_i*P_i^c \]
其中 \(N\) 是圖像數量,\(P_i\) 是曝光集合中的第 \(i\) 個圖像,\(W_i\) 是第 \(i\) 個圖像的權重圖,\(c\) 是三個顏色通道的索引,\(R\) 是增強后的結果。三個顏色分量是相等的,所有像素是不均勻的:曝光良好的像素具有較大的權重,曝光不良的像素權重較小。權重已標準化,因此 \(\sum_{i=1}^{N}W_i=1\)

問題是具有其他曝光設置的圖像不適用於圖像增強問題。幸運的是,使用不同的曝光度拍攝的照片是高度相關的。在我們的早期工作中,我們提出了相機響應模型以準確描述這些圖像之間的關聯,以便我們從輸入圖像生成一系列圖像。兩張不同曝光度的圖像的映射函數,我們稱為亮度轉換函數(BTF)。給定曝光率 \(k_i\) 和 亮度轉換函數 \(g\),我們可以映射輸入圖像 \(P\) 到曝光集合中的第 \(i\) 個圖像:
\[ P_i=g(P, k_i) \]
在本文中,我們僅以一定的曝光融合輸入圖像本身來降低複雜度,如圖2所示。融合圖像定義為:
\[ R^c=W*P^c+(1-W)*g(P^c,k) \]

增強問題可分為三個部分:\(W, g, k\) 的三個參數的估計。在以下小節中,我們將一一解決這三個問題。

2.2 權重矩陣估計

\(W\) 是增強算法的關鍵,其目的是增強曝光不足區域的低對比度,而保留曝光良好區域的對比度。我們需要給曝光良好的像素分配較大的權重值,給曝光不足的像素分配較小的權重值。直觀地來說,權重矩陣與場景光照正相關。由於高度光照區域有更大的可能性獲得更好的曝光,應分配給大的權重值以保持它們的對比度。我們計算權重矩陣為:
\[ W=T^{\mu} \]
其中 \(T\) 是場景光照圖,\(\mu\) 是控制增強程度的參數。場景光照估計位置映射 \(T\) 通過優化的方法解決。

(1)優化問題

亮度分量可以作為場景光照的估計。我們採用亮度分量作為光照估計的初始值:
\[ L(x)=max _{c\in \{R,G,B\}}P_c(x) \]
對於每個單獨的像素x。理想照明在結構相似的區域具有局部一致性。換句話說,\(T\) 應該保持有意義的圖像的結構並去除紋理邊緣。在文獻[5]中,我們可以通過最優方程得到 \(T\)
\[ \min _{\mathbf{T}}\|\mathbf{T}-\mathbf{L}\|_{2}^{2}+\lambda\|\mathbf{M} \circ \nabla \mathbf{T}\|_{1} \]
其中 \(\|*\|_2\)\(\|*\|_1\) 分別是 \(\ell_2\)\(\ell_1\) 范數。一階微分濾波器 \(\nabla\) 包含水平方向梯度 \(\nabla_h\mathbf{T}\) 和垂直方向梯度 \(\nabla_v\mathbf{T}\)\(M\) 是權重矩陣,\(\lambda\) 是係數。方程式的第一項最小化初始圖 \(\mathbf{L}\)和場景光照圖\(\mathbf{T}\),而第二項為保證 \(\mathbf{T}\) 的平滑性。

\(\mathbf{M}\) 的設計對於光照圖的細化很重要。局部窗口中的主要邊緣比具有複雜圖案的紋理貢獻了更多的相似方向梯度。因此,包含有意義的邊緣窗口中的權重應小於僅包含一個窗口的邊緣紋理。因此,我們將權重矩陣設計為
\[ \mathbf{M}_{d}(x)=\frac{1}{\left|\sum_{y \in \omega(x)} \nabla_{d} \mathbf{L}(y)\right|+\epsilon}, \quad d \in\{h, v\} \]
其中\(| ∗ |\) 是絕對值運算符,\(\omega(x)\) 是以像素 \(x\)\(\epsilon\) 是一個很小的常數,以避免分母為零。

(2)封閉解

為了簡化複雜度,我們將Eq.6近似為在文獻[5]中公式:
\[ \min _{\mathbf{T}} \sum_{x}\left((\mathbf{T}(x)-\mathbf{L}(x))^{2}+\lambda \sum_{d \in\{h, v\}} \frac{\mathbf{M}_{d}(x)\left(\nabla_{d} \mathbf{T}(x)\right)^{2}}{\left|\nabla_{d} \mathbf{L}(x)\right|+\epsilon}\right) \]
可以看出,該式子現在僅涉及二次項。 令\(md\)\(l\)\(t\)\(\nabla_dl\) 分別表示向量化的\(\mathbf{M}_d\)\(\mathbf{L}\)\(\mathbf{T}\)\(\nabla_d \mathbf{L}\)。 然後可以通過求解以下線性函數直接獲得解
\[ \left(\mathbf{I}+\lambda \sum_{d \in\{h, v\}}\left(\mathbf{D}_{\mathbf{d}}^{\top} \operatorname{Diag}\left(\mathbf{m}_{d} \oslash\left(\left|\nabla_{d} \mathbf{l}\right|+\epsilon\right)\right) \mathbf{D}_{\mathbf{d}}\right) \mathbf{t}=1\right. \]
其中\(\varnothing\)是按元素劃分,\(\mathbf{I}\) 是單位矩陣,運算符 \(Diag(v)\) 是用向量 \(v\) 構造對角矩陣,\(\mathbf{D}_d\) 是Toeplitz矩陣來自具有前向差異的離散梯度算子。我們的光照圖估計方法和文獻[5]的主要區別是設計矩陣\(\mathbf{M}\) 的權重。我們採用了簡化的策略,可以產生在文獻[5]中相似的結果。基於Retinex的其他光照分解技術方法可以運用到這裏來找到權重矩陣 \(\mathbf{W}\)

2.3 相機響應模型

在我們的早期工作中,我們提出了一個稱為Beta-Gamma的相機響應模型校正模型在文獻[[16]中。我們模型的BTF定義為:
\[ g(\mathbf{P},k)=\beta\mathbf{P^{\gamma}}=e^{b(1-k^a)\mathbf{P^{(k^a)}}} \]
其中 \(\beta\)\(\gamma\) 是該模型的兩個參數,可以通過相機參數 \(a\)\(b\) 和曝光率 \(k\) 計算得到。我們假設沒有任何相機信息,並使用固定相機參數(\(a = -0.3293\)\(b = 1.1258\))可以適配大多數相機。

2.4 確定曝光率

在本小節中,我們找到最佳的曝光率,以便合成圖像在原始圖像曝光不足的區域中曝光良好。第一,我們排除曝光良好的像素,並獲得整體上低曝光圖像。我們只需提取低光照像素為:
\[ \mathbf{Q}=\{\mathbf{P}(x)\mathbf{T}(x)<0.5\} \]
其中 \(\mathbf{Q}\) 僅包含曝光不足的像素。不同曝光下圖像的亮度變化很大但是顏色基本相同。因此,我們在估計 \(k\) 只考慮了亮度分量。亮度分量 \(\mathbf{B}\) 定義為三個通道的幾何平均值:
\[ \mathbf{B}:=\sqrt[3]{\mathbf{Q}_r\circ\mathbf{Q}_g\circ\mathbf{Q}_b} \]
其中\(\mathbf{Q}_r\)\(\mathbf{Q}_g\)\(\mathbf{Q}_b\) 分別是輸入圖像 \(\mathbf{Q}\) 的紅色,綠色和藍色通道。 我們使用幾何平均值代替其他定義(例如算術平均值和加權算術平均值),因為它具有相同的BTF所有三個顏色通道的模型參數( \(\beta\)\(\gamma\)),如下所示:
\[ \begin{aligned} \mathbf{B}^{\prime} &:=\sqrt[3]{\mathbf{Q}_{r}^{\prime} \circ \mathbf{Q}_{g}^{\prime} \circ \mathbf{Q}_{b}^{\prime}} \\ &=\sqrt[3]{\left(\beta \mathbf{Q}_{r}^{\gamma}\right) \circ\left(\beta \mathbf{Q}_{g}^{\gamma}\right) \circ\left(\beta \mathbf{Q}_{b}^{\gamma}\right)}=\beta(\sqrt[3]{\mathbf{Q}_{r} \circ \mathbf{Q}_{g} \circ \mathbf{Q}_{b}})^{\gamma} \\ &=\beta \mathbf{B}^{\gamma} \end{aligned} \]
曝光良好的圖像的可見度高於曝光不足的圖像,它可以為人類提供更豐富的信息。因此,最優的 \(k\) 應該提供最多的信息。為了衡量信息的數量,我們使用圖像熵來定義:
\[ \mathcal{H}(\mathbf{B})=-\sum_{i=1}^{N} p_{i} \cdot \log _{2} p_{i} \]
其中 \(p_i\) 是B的直方圖的第i個bin,用於計算數據數量在 \([\frac{i}{N},\frac{i=1}{N}]\),N是bin數( \(N\) 通常設置為256)。最後,通過最大化圖像增強的亮度熵來計算最佳 \(k\) 值:
\[ \hat{k}=\underset{k}{\operatorname{argmax}} \mathcal{H}(g(\mathbf{B}, k)) \]
最優的 \(k\) 值可以通過一維最小化求解。為了改善計算效率,我們在優化 \(k\) 時將輸入圖像的大小調整為 \(50 \times 50\)

3. 實驗對比

為了評估我們方法的性能,我們在公開數據集與幾種最新技術(AMSR [9],LIME [5],Dong [4]和NPE [14])進行比較。這五個公共數據集分別為:VV,LIME-data [5],NPE [14](NPEdata,NPE-ex1,NPE-ex2和NPE-ex3),MEF [10]和IUS [8]。 MEF和IUS是多重曝光數據集,我們從每個多重曝光中選擇一個弱光圖像進行評估。

3.1 實驗細節

在我們的算法中,\(\mu\) 是控制整體增強程度的參數。當\(\mu = 0\)時,所得 \(\mathbf{R}\) 等於 \(\mathbf{P}\),即沒有增強效果。 當時,曝光不足像素和曝光良好像素均被增強。 當 \(\mu> 1\) 時,像素可能會飽和,從而導致 \(R\) 遭受細節損失。 為了更好的增強,同時保留曝光良好的區域,我們將 \(\mu\) 設置為1/2。

為了保持比較的公平性,我們增強算法的參數在所有實驗中都是固定的:\(\lambda = 1\)\(\epsilon=0.001\)\(\mu= 1/2\),和局部窗口\(\omega(x)\)的大小為5。我們算法中最耗時的部分是光照圖的優化。 我們採用多分辨率共軛梯度 \((\mathbf{O}(N))\) 來有效地求解它。 為了進一步加快我們的算法,我們通過對輸入圖像進行下採樣方法解決 \(\mathbf{T}\),然後將生成的 \(\mathbf{T}\) 向上採樣到原始大小。 如果我們向下採樣一次,增強結果中沒有視覺差異,但是計算效率大大提高了。

3.2 對比度失真

如前所述,僅曝光度不同的圖像可用作參考來評估增強結果準確性。 DRIM(動態範圍獨立指標)[1]可以測量圖像對比度的失真,而無需考慮圖像亮度變化。 我們用它來可視化對比增強結果與參考圖像之間的差異。

如圖3所示,該方法得到失真最小的結果。 Dong的結果出現嚴重的對比度失真。 儘管AMSR可以恢復細節,但對比度明顯下降使結果看起來暗淡和虛幻。 相比之下,LIME的結果看起來像有點生動,但它們會導致放大不可見的對比度。 圖5显示更多示例在視覺上進行比較。

3.3 亮度失真

我們用我們使用亮度等級誤差(LOE)客觀地衡量增強結果的亮度失真。 LOE定義為:
\[ LOE=\frac{1}{m}\sum_{x=1}^{m}RD(x) \]
對於像素 \(x\), 其中 \(RD(x)\) 是原始圖像 \(P\) 和增強后\(P^{‘}\) 之間的相對亮度階差,其定義如下:
\[ RD(x)=\sum_{y=1}^{m} U(\mathbf{L}(x), \mathbf{L}(y)) \oplus U\left(\mathbf{L}^{\prime}(x), \mathbf{L}^{\prime}(y)\right) \]
其中 \(m\) 是像素數量,\(\oplus\) 表示異或運算符,\(\mathbf{L}(x)\)\(\mathbf{L}^{\prime}(x)\) 分別是輸入圖像和增強后位置 \(x\) 處的亮度分量。 如果 \(p>= q\),函數 \(U(p,q)\) 返回1,其他情況為0。

正如[5,14]中所建議的那樣,下採樣用於計算LOE降低複雜度。 由於RD將隨着像素數量m的增加而增加,我們注意到LOE隨着圖片下採樣為不同尺寸而變化。 因此,我們將所有圖像下採樣到固定大小。 具體來說,我們均勻收集100行和列,以形成 \(100\times100\) 的下採樣圖像。如表1所示,我們的算法在所有數據集中均優於其他算法。 這個意味着我們的算法可以很好地保持圖像的自然性。 我們也提供了圖4中兩種情況的亮度失真的可視化,從中我們可以發現我們的結果具有最小的亮度失真。AMSR的結果失去了全局的亮度等級,並具有最大的亮度失真。儘管LIME的結果在視覺上令人愉悅,但它們也存在亮度不足的失真。 Dong和NPE的結果只能在曝光良好的區域保留亮度順序。

4. 結論

在本文中,我們提出了曝光融合框架和增強算法提供精確的對比度增強的算法。 基於我們的框架,我們解決了三個問題:(1)我們借鑒了光照估算技術獲得圖像融合的權重矩陣。(2)通過相機響應模型來合成多重曝光圖像。(3)我們找到了最好的曝光率,使合成圖像在原始圖像曝光不足的區域曝光良好。 最終的增強結果是通過融合根據權重矩陣對輸入圖像和合成圖像進行處理。實驗結果表明我們方法相比現階段最先進的方案的有效性。
可以在我們的項目網站上找到更多測試結果:。

5. 主要參考文獻

  1. Aydin, T.O., Mantiuk, R., Myszkowski, K., Seidel, H.P.: Dynamic range independent image quality assessment. ACM Trans. Graph. (TOG) 27(3), 69 (2008)
  2. Beghdadi, A., Le Negrate, A.: Contrast enhancement technique based on local detection of edges. Comput. Vis. Graph. Image Process. 46(2), 162–174 (1989)
  3. Chen, S.D., Ramli, A.R.: Minimum mean brightness error bi-histogram equalization in contrast enhancement. IEEE Trans. Consum. Electron. 49(4), 1310–1319(2003)
  4. Dong, X., Wang, G., Pang, Y., Li, W., Wen, J., Meng, W., Lu, Y.: Fast efficient algorithm for enhancement of low lighting video. In: 2011 IEEE International Conference on Multimedia and Expo, pp. 1–6. IEEE (2011)
  5. Guo, X.: Lime: a method for low-light image enhancement. In: Proceedings of the 2016 ACM on Multimedia Conference, pp. 87–91. ACM (2016)
  6. Ibrahim, H., Kong, N.S.P.: Brightness preserving dynamic histogram equalization for image contrast enhancement. IEEE Trans. Consum. Electron. 53(4), 1752–1758 (2007)
  7. Jobson, D.J., Rahman, Z., Woodell, G.A.: A multiscale retinex for bridging the gap between color images and the human observation of scenes. IEEE Trans. Image Process. 6(7), 965–976 (1997)
  8. Karaduzovic-Hadziabdic, K., Telalovic, J.H., Mantiuk, R.: Subjective and objective evaluation of multi-exposure high dynamic range image deghosting methods (2016)
  9. Lee, C.H., Shih, J.L., Lien, C.C., Han, C.C.: Adaptive multiscale retinex for image contrast enhancement. In: 2013 International Conference on Signal-Image Technology & Internet-Based Systems (SITIS), pp. 43–50. IEEE (2013)
  10. Ma, K., Zeng, K., Wang, Z.: Perceptual quality assessment for multi-exposure image fusion. IEEE Trans. Image Process. 24(11), 3345–3356 (2015)
  11. Peli, E.: Contrast in complex images. JOSA A 7(10), 2032–2040 (1990)
  12. Reza, A.M.: Realization of the contrast limited adaptive histogram equalization (clahe) for real-time image enhancement. J. VLSI Signal Process. Syst. Signal Image Video Technol. 38(1), 35–44 (2004)
  13. Wang, C., Ye, Z.: Brightness preserving histogram equalization with maximum entropy: a variational perspective. IEEE Trans. Consum. Electron. 51(4), 1326– 1334 (2005)
  14. Wang, S., Zheng, J., Hu, H.M., Li, B.: Naturalness preserved enhancement algorithm for non-uniform illumination images. IEEE Trans. Image Process. 22(9), 3538–3548 (2013)
  15. Xu, L., Yan, Q., Xia, Y., Jia, J.: Structure extraction from texture via relative total variation. ACM Trans. Graph. (TOG) 31(6), 139 (2012)
  16. Ying, Z., Li, G., Ren, Y., Wang, R., Wang, W.: A new low-light image enhancement algorithm using camera response model, manuscript submitted for publication (2017)

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

※廣告預算用在刀口上,網站設計公司幫您達到更多曝光效益

※自行創業 缺乏曝光? 下一步"網站設計"幫您第一時間規劃公司的門面形象

南投搬家前需注意的眉眉角角,別等搬了再說!

2015年特斯拉共銷售50580輛電動汽車 完成年度銷售計畫

據報導,特斯拉日前宣佈2015年銷售了50580輛電動汽車,完成年度銷售計畫。

特斯拉稱,2015年第四季度Model S電動汽車銷量為17192輛,比上年同期增長75%,環比增長48%。該公司第四季度生產507輛Model X電動汽車,銷售208輛。特斯拉目前計畫每週生產238輛Model X。

特斯拉完成年度銷售計畫相當重要。特斯拉一直在嘗試大幅提高Model S產量,並首次生產Model X。

這是一個頗為困難的任務。特斯拉最初計畫2015年銷售55000輛電動汽車。由於同時生產兩款車型存在不少困難,特斯拉去年8月把銷售目標下調至50000-55000輛,去年11月份再次把銷售目標下調至50000-52000輛。

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※帶您來了解什麼是 USB CONNECTOR  ?

※自行創業 缺乏曝光? 下一步"網站設計"幫您第一時間規劃公司的門面形象

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!!

※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

※廣告預算用在刀口上,網站設計公司幫您達到更多曝光效益

讓特斯拉再飛一會兒,GM 不介意在電動車市場落後

特斯拉無疑是目前電動車領域的領先者,從電池、馬達到控制元件都比各大車廠先進,然而通用汽車並不擔心,儘管特斯拉在 2019 年賣出破紀錄的 37 萬輛車,仍然離通用的 290 萬輛非常遙遠。

上個月才宣布經典悍馬車電動化的消息,通用汽車(GM)手上還有越賣越賠錢的 Chevy Bolt,這兩款電動車從價格與性能來看,都不是特斯拉的對手,事實上目前市面大部分電動車都不是,但為什麼這些大車廠似乎不太擔心?

「我們預估今年車市會持續低迷,美國市場約會下滑 50 萬輛」,GM 財務長迪瓦‧蘇里亞帝娃拉(Dhivya Suryadevara)預估,中國跟南美洲也同樣會繼續衰退。

一片悲觀中,特斯拉一枝獨秀的股價讓 GM 看起來毫無抵抗之力,不過這些老車廠可不像股價看起來這麼脆弱。

特斯拉去年創下銷售新高紀錄,總共售出約 37 萬輛電動車,但虧損 8.25 億美元(第三、第四季為正);通用汽車則賣出 290 萬輛車,利潤 67 億美元。市場雖然寵愛特斯拉,但當這些大廠開始砸錢時,規模非常驚人。

GM 最近陸續宣布要改建底特律廠,當作電動車與自駕車專用產線;同時還與南韓 LG Chem 合作興建新電池廠,總共投入 45 億美元,但什麼時候要真的把錢砸下去,還在看正確的時間點。

電動車的獲利關鍵:電池成本

「對 GM 來說,不介意在市場讓特斯拉領先,之後再砸大錢追上它。」彭博汽車產業分析師 Kevin Tynan 認為,當電動車真正能獲利時,GM 隨時都能衝出大量產能並快速生產。

隨著政府補貼逐漸縮水或退場,特斯拉的高價車款銷量大幅下滑,而在市場快速成長的 Model 3 最終也只在去年幫特斯拉多賺了 0.3% 營收。

電動車要能賺錢,關鍵還是回到製造成本,尤其是電池成本,想要降低成本就必須靠技術突破,然而特斯拉已經在 2019 第三季開始放慢資本支出的速度,以彌補前兩季的虧損,整個 2019 年資本支出跟前一年幾乎相同,因此才能在上一季交出漂亮財報,同時帶動股價一飛沖天。

反觀通用汽車,即使去年遭遇勞資問題,導致 36 億美元損失,全年獲利還是高達 67 億美元,面對萎縮的全球車市,GM 還是預估休旅車跟皮卡車能維持不錯獲利,而這些收入都將持續投入電池與電動車技術開發。

GM 電池工程總監 Tim Grewe 認為,要開發擁有價格效益的電池,還需要更先進的科技,而這些科技如今都還沒實現。在那之前,特斯拉將會持續稱霸電動車銷售市場,並繼續虧損。

最近特斯拉除了推進自行研發電池的進度,也在研討與寧德時代合作無鈷電池,以降低電池成本。這場電動車電池的爭戰,GM 決定讓特斯拉再飛一會,但會不會一不小心,就飛到再也追不到的地方了?

(合作媒體:。首圖來源:)

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

※廣告預算用在刀口上,網站設計公司幫您達到更多曝光效益

※自行創業 缺乏曝光? 下一步"網站設計"幫您第一時間規劃公司的門面形象

南投搬家前需注意的眉眉角角,別等搬了再說!

5種常見Bean映射工具的性能比對

本文由 JavaGuide 翻譯自 https://www.baeldung.com/java-performance-mapping-frameworks 。轉載請註明原文地址以及翻譯作者。

1. 介紹

創建由多個層組成的大型 Java 應用程序需要使用多種領域模型,如持久化模型、領域模型或者所謂的 DTO。為不同的應用程序層使用多個模型將要求我們提供 bean 之間的映射方法。手動執行此操作可以快速創建大量樣板代碼並消耗大量時間。幸運的是,Java 有多個對象映射框架。在本教程中,我們將比較最流行的 Java 映射框架的性能。

綜合日常使用情況和相關測試數據,個人感覺 MapStruct、ModelMapper 這兩個 Bean 映射框架是最佳選擇。

2. 常見 Bean 映射框架概覽

2.1. Dozer

Dozer 是一個映射框架,它使用遞歸將數據從一個對象複製到另一個對象。框架不僅能夠在 bean 之間複製屬性,還能夠在不同類型之間自動轉換。

要使用 Dozer 框架,我們需要添加這樣的依賴到我們的項目:

<dependency>
    <groupId>net.sf.dozer</groupId>
    <artifactId>dozer</artifactId>
    <version>5.5.1</version>
</dependency>

更多關於 Dozer 的內容可以在官方文檔中找到: http://dozer.sourceforge.net/documentation/gettingstarted.html ,或者你也可以閱讀這篇文章:https://www.baeldung.com/dozer 。

2.2. Orika

Orika 是一個 bean 到 bean 的映射框架,它遞歸地將數據從一個對象複製到另一個對象。

Orika 的工作原理與 Dozer 相似。兩者之間的主要區別是 Orika 使用字節碼生成。這允許以最小的開銷生成更快的映射器。

要使用 Orika 框架,我們需要添加這樣的依賴到我們的項目:

<dependency>
    <groupId>ma.glasnost.orika</groupId>
    <artifactId>orika-core</artifactId>
    <version>1.5.2</version>
</dependency>

更多關於 Orika 的內容可以在官方文檔中找到:https://orika-mapper.github.io/orika-docs/,或者你也可以閱讀這篇文章:https://www.baeldung.com/orika-mapping。

2.3. MapStruct

MapStruct 是一個自動生成 bean mapper 類的代碼生成器。MapStruct 還能夠在不同的數據類型之間進行轉換。Github 地址:https://github.com/mapstruct/mapstruct。

要使用 MapStruct 框架,我們需要添加這樣的依賴到我們的項目:

<dependency>
    <groupId>org.mapstruct</groupId>
    <artifactId>mapstruct-processor</artifactId>
    <version>1.2.0.Final</version>
</dependency>

更多關於 MapStruct 的內容可以在官方文檔中找到:https://mapstruct.org/,或者你也可以閱讀這篇文章:https://www.baeldung.com/mapstruct。

要使用 MapStruct 框架,我們需要添加這樣的依賴到我們的項目:

<dependency>
    <groupId>org.mapstruct</groupId>
    <artifactId>mapstruct-processor</artifactId>
    <version>1.2.0.Final</version>
</dependency>

2.4. ModelMapper

ModelMapper 是一個旨在簡化對象映射的框架,它根據約定確定對象之間的映射方式。它提供了類型安全的和重構安全的 API。

更多關於 ModelMapper 的內容可以在官方文檔中找到:http://modelmapper.org/ 。

要使用 ModelMapper 框架,我們需要添加這樣的依賴到我們的項目:

<dependency>
  <groupId>org.modelmapper</groupId>
  <artifactId>modelmapper</artifactId>
  <version>1.1.0</version>
</dependency>

2.5. JMapper

JMapper 是一個映射框架,旨在提供易於使用的、高性能的 Java bean 之間的映射。該框架旨在使用註釋和關係映射應用 DRY 原則。該框架允許不同的配置方式:基於註釋、XML 或基於 api。

更多關於 JMapper 的內容可以在官方文檔中找到:https://github.com/jmapper-framework/jmapper-core/wiki。

要使用 JMapper 框架,我們需要添加這樣的依賴到我們的項目:

<dependency>
    <groupId>com.googlecode.jmapper-framework</groupId>
    <artifactId>jmapper-core</artifactId>
    <version>1.6.0.1</version>
</dependency>

3.測試模型

為了能夠正確地測試映射,我們需要有一個源和目標模型。我們已經創建了兩個測試模型。

第一個是一個只有一個字符串字段的簡單 POJO,它允許我們在更簡單的情況下比較框架,並檢查如果我們使用更複雜的 bean 是否會發生任何變化。

簡單的源模型如下:

public class SourceCode {
    String code;
    // getter and setter
}

它的目標也很相似:

public class DestinationCode {
    String code;
    // getter and setter
}

源 bean 的實際示例如下:

public class SourceOrder {
    private String orderFinishDate;
    private PaymentType paymentType;
    private Discount discount;
    private DeliveryData deliveryData;
    private User orderingUser;
    private List<Product> orderedProducts;
    private Shop offeringShop;
    private int orderId;
    private OrderStatus status;
    private LocalDate orderDate;
    // standard getters and setters
}

目標類如下圖所示:

public class Order {
    private User orderingUser;
    private List<Product> orderedProducts;
    private OrderStatus orderStatus;
    private LocalDate orderDate;
    private LocalDate orderFinishDate;
    private PaymentType paymentType;
    private Discount discount;
    private int shopId;
    private DeliveryData deliveryData;
    private Shop offeringShop;
    // standard getters and setters
}

整個模型結構可以在這裏找到:https://github.com/eugenp/tutorials/tree/master/performance-tests/src/main/java/com/baeldung/performancetests/model/source。

4. 轉換器

為了簡化測試設置的設計,我們創建了如下所示的轉換器接口:

public interface Converter {
    Order convert(SourceOrder sourceOrder);
    DestinationCode convert(SourceCode sourceCode);
}

我們所有的自定義映射器都將實現這個接口。

4.1. OrikaConverter

Orika 支持完整的 API 實現,這大大簡化了 mapper 的創建:

public class OrikaConverter implements Converter{
    private MapperFacade mapperFacade;

    public OrikaConverter() {
        MapperFactory mapperFactory = new DefaultMapperFactory
          .Builder().build();

        mapperFactory.classMap(Order.class, SourceOrder.class)
          .field("orderStatus", "status").byDefault().register();
        mapperFacade = mapperFactory.getMapperFacade();
    }

    @Override
    public Order convert(SourceOrder sourceOrder) {
        return mapperFacade.map(sourceOrder, Order.class);
    }

    @Override
    public DestinationCode convert(SourceCode sourceCode) {
        return mapperFacade.map(sourceCode, DestinationCode.class);
    }
}

4.2. DozerConverter

Dozer 需要 XML 映射文件,有以下幾個部分:

<mappings xmlns="http://dozer.sourceforge.net"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://dozer.sourceforge.net
  http://dozer.sourceforge.net/schema/beanmapping.xsd">

    <mapping>
        <class-a>com.baeldung.performancetests.model.source.SourceOrder</class-a>
        <class-b>com.baeldung.performancetests.model.destination.Order</class-b>
        <field>
            <a>status</a>
            <b>orderStatus</b>
        </field>
    </mapping>
    <mapping>
        <class-a>com.baeldung.performancetests.model.source.SourceCode</class-a>
        <class-b>com.baeldung.performancetests.model.destination.DestinationCode</class-b>
    </mapping>
</mappings>

定義了 XML 映射后,我們可以從代碼中使用它:

public class DozerConverter implements Converter {
    private final Mapper mapper;

    public DozerConverter() {
        DozerBeanMapper mapper = new DozerBeanMapper();
        mapper.addMapping(
          DozerConverter.class.getResourceAsStream("/dozer-mapping.xml"));
        this.mapper = mapper;
    }

    @Override
    public Order convert(SourceOrder sourceOrder) {
        return mapper.map(sourceOrder,Order.class);
    }

    @Override
    public DestinationCode convert(SourceCode sourceCode) {
        return mapper.map(sourceCode, DestinationCode.class);
    }
}

4.3. MapStructConverter

Map 結構的定義非常簡單,因為它完全基於代碼生成:

@Mapper
public interface MapStructConverter extends Converter {
    MapStructConverter MAPPER = Mappers.getMapper(MapStructConverter.class);

    @Mapping(source = "status", target = "orderStatus")
    @Override
    Order convert(SourceOrder sourceOrder);

    @Override
    DestinationCode convert(SourceCode sourceCode);
}

4.4. JMapperConverter

JMapperConverter 需要做更多的工作。接口實現后:

public class JMapperConverter implements Converter {
    JMapper realLifeMapper;
    JMapper simpleMapper;

    public JMapperConverter() {
        JMapperAPI api = new JMapperAPI()
          .add(JMapperAPI.mappedClass(Order.class));
        realLifeMapper = new JMapper(Order.class, SourceOrder.class, api);
        JMapperAPI simpleApi = new JMapperAPI()
          .add(JMapperAPI.mappedClass(DestinationCode.class));
        simpleMapper = new JMapper(
          DestinationCode.class, SourceCode.class, simpleApi);
    }

    @Override
    public Order convert(SourceOrder sourceOrder) {
        return (Order) realLifeMapper.getDestination(sourceOrder);
    }

    @Override
    public DestinationCode convert(SourceCode sourceCode) {
        return (DestinationCode) simpleMapper.getDestination(sourceCode);
    }
}

我們還需要向目標類的每個字段添加@JMap註釋。此外,JMapper 不能在 enum 類型之間轉換,它需要我們創建自定義映射函數:

@JMapConversion(from = "paymentType", to = "paymentType")
public PaymentType conversion(com.baeldung.performancetests.model.source.PaymentType type) {
    PaymentType paymentType = null;
    switch(type) {
        case CARD:
            paymentType = PaymentType.CARD;
            break;

        case CASH:
            paymentType = PaymentType.CASH;
            break;

        case TRANSFER:
            paymentType = PaymentType.TRANSFER;
            break;
    }
    return paymentType;
}

4.5. ModelMapperConverter

ModelMapperConverter 只需要提供我們想要映射的類:

public class ModelMapperConverter implements Converter {
    private ModelMapper modelMapper;

    public ModelMapperConverter() {
        modelMapper = new ModelMapper();
    }

    @Override
    public Order convert(SourceOrder sourceOrder) {
       return modelMapper.map(sourceOrder, Order.class);
    }

    @Override
    public DestinationCode convert(SourceCode sourceCode) {
        return modelMapper.map(sourceCode, DestinationCode.class);
    }
}

5. 簡單的模型測試

對於性能測試,我們可以使用 Java Microbenchmark Harness,關於如何使用它的更多信息可以在 這篇文章:https://www.baeldung.com/java-microbenchmark-harness 中找到。

我們為每個轉換器創建了一個單獨的基準測試,並將基準測試模式指定為 Mode.All。

5.1. 平均時間

對於平均運行時間,JMH 返回以下結果(越少越好):

這個基準測試清楚地表明,MapStruct 和 JMapper 都有最佳的平均工作時間。

5.2. 吞吐量

在這種模式下,基準測試返回每秒的操作數。我們收到以下結果(越多越好):

在吞吐量模式中,MapStruct 是測試框架中最快的,JMapper 緊隨其後。

5.3. SingleShotTime

這種模式允許測量單個操作從開始到結束的時間。基準給出了以下結果(越少越好):

這裏,我們看到 JMapper 返回的結果比 MapStruct 好得多。

5.4. 採樣時間

這種模式允許對每個操作的時間進行採樣。三個不同百分位數的結果如下:

所有的基準測試都表明,根據場景的不同,MapStruct 和 JMapper 都是不錯的選擇,儘管 MapStruct 對 SingleShotTime 給出的結果要差得多。

6. 真實模型測試

對於性能測試,我們可以使用 Java Microbenchmark Harness,關於如何使用它的更多信息可以在 這篇文章:https://www.baeldung.com/java-microbenchmark-harness 中找到。

我們為每個轉換器創建了一個單獨的基準測試,並將基準測試模式指定為 Mode.All。

6.1. 平均時間

JMH 返回以下平均運行時間結果(越少越好):

該基準清楚地表明,MapStruct 和 JMapper 均具有最佳的平均工作時間。

6.2. 吞吐量

在這種模式下,基準測試返回每秒的操作數。我們收到以下結果(越多越好):

在吞吐量模式中,MapStruct 是測試框架中最快的,JMapper 緊隨其後。

6.3. SingleShotTime

這種模式允許測量單個操作從開始到結束的時間。基準給出了以下結果(越少越好):

6.4. 採樣時間

這種模式允許對每個操作的時間進行採樣。三個不同百分位數的結果如下:

儘管簡單示例和實際示例的確切結果明顯不同,但是它們的趨勢相同。在哪種算法最快和哪種算法最慢方面,兩個示例都給出了相似的結果。

6.5. 結論

根據我們在本節中執行的真實模型測試,我們可以看出,最佳性能顯然屬於 MapStruct。在相同的測試中,我們看到 Dozer 始終位於結果表的底部。

7. 總結

在這篇文章中,我們已經進行了五個流行的 Java Bean 映射框架性能測試:ModelMapper MapStruct Orika ,Dozer, JMapper。

示例代碼地址:https://github.com/eugenp/tutorials/tree/master/performance-tests。

開源項目推薦

作者的其他開源項目推薦:

  1. :【Java學習+面試指南】 一份涵蓋大部分Java程序員所需要掌握的核心知識。
  2. : 適合新手入門以及有經驗的開發人員查閱的 Spring Boot 教程(業餘時間維護中,歡迎一起維護)。
  3. : 我覺得技術人員應該有的一些好習慣!
  4. :從零入門 !Spring Security With JWT(含權限驗證)後端部分代碼。

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】

※帶您來了解什麼是 USB CONNECTOR  ?

※自行創業 缺乏曝光? 下一步"網站設計"幫您第一時間規劃公司的門面形象

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!!

※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

※廣告預算用在刀口上,網站設計公司幫您達到更多曝光效益

台日合作電動車「日台之翼」 日本參賽奪佳績

  南臺科技大學與日本姊妹校三重大學跨國跨校合作,組團參加日本鈴鹿賽道所舉辦的「2015 Ene-1 GP SUZUKA」新世代能源車競賽,「日台之翼」以 25 分 03 秒636成績在全部 89 個參賽隊伍中勇奪第 10 名,在所有參賽的大專隊伍中則名列第 2,由於兩校聯合組隊,無法參加專科以上學校組別,因而歸屬一般組(社會組)中排名第 6,以第一年參賽隊伍而言,成績表現十分亮眼。   其競賽方式是以 40 顆市售 3 號電池為電源的電動車競速賽,行駛於鈴鹿賽車道 3 圈,並以總時間長短決定勝負。南臺科大校長戴謙表示,此次競賽用車「日台之翼」為日本三重大學電機系師生組裝車輛,南臺科大提供車輛測試與行駛數據分析,並由台灣大魯閣集團贊助車體與車輛零件,攜手合作完成。   有鑑於南臺科大機械系已有 20 年長期製作車輛如太陽能車、方程式賽車、燃料電池車、環保電車等技術與經驗,日本三重大學決定與南臺科大攜手合作,製作電動車共同參賽。     (圖片來源:)

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※帶您來了解什麼是 USB CONNECTOR  ?

※自行創業 缺乏曝光? 下一步"網站設計"幫您第一時間規劃公司的門面形象

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!!

※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

※廣告預算用在刀口上,網站設計公司幫您達到更多曝光效益

電動車將造成下個石油崩跌危機:BNEF

電動車目前佔車市的市佔仍然相當低,油國與石油業界對電動車也一向相當輕視,各項預測與未來石油產銷報告中往往都認為電動車的影響可略,不過,彭博新能源財經(Bloomberg New Energy Finance)的看法與他們相左,預言電動車將大行其道,而造成下一次油價崩跌危機。   目前電動車與充電式油電混合車只佔全球車市的 0.1%,在多數國家中都相當少見,而且車價也遠比汽油車高,油國組織(OPEC)十分輕視電動車的發展,認為到 2040 年電動車也只會佔車市的 1%,而石油業巨頭康菲(ConocoPhillips)也一樣不把電動車當一回事,執行長萊恩蘭斯(Ryan Lance)表示,電動車在 50 年內,甚至在他畢生之內,都不會有實際的影響力,另一家石油巨擘艾克森美孚(Exxon)也看扁電動車市佔只能達到 2%。   然而彭博新能源財經的看法完全相左,認為 2020 年代就會是電動車的時代。電動車的基本經濟層面逐漸往有利的方向發展,其中最重要的就是佔成本相當大比例的電池,在 2015 年電池成本下降 35%,以這個下降速度,6 年內電動車就會比汽油車更具經濟效益,電動車將會迎來市場起飛期,到 2040 年時,長程電動車將要價不到 2.2 萬美元,相當於約 73 萬元新台幣,在這樣的親民價格下,屆時全球 35% 新車銷售都將是電動車。   事實上,不用看到那麼遙遠,就在幾年內,不論是特斯拉(Tesla),雪佛蘭(Chevrolet)、日產(Nissan)等車廠都計劃推出 3 萬美元價位的長程電動車,相當於約百萬元新台幣,其他車廠與 IT 大廠則正投注數以十億美元計的資本,進行相關技術與車種的研發,預期到 2020 年,部分電動車種將會售價比同級汽油車便宜,效能還更好,屆時許多電動車將會銷售勝過同級汽油車,事實上,不用到 2020 年,目前特斯拉的 Model S 銷售就已經勝過同級的汽油高級車。   2015 年電動車銷售成長 60%,大體上與特斯拉預期到 2020 年為止的每年年成長率一致,在歷史上,這也剛好正是福特 T 型車當初取代馬車時的成長率,因此,與石油界所想的相反,電動車起飛很快會對石油需求發生實際影響,彭博社計算,若是電動車繼續以 60% 年成長率成長,最早至 2023 年,而若以比較精確的成長模型計算,至 2028 年,電動車將會減少每日 200 萬桶石油需求,而 2014 年石油價格大崩盤,其實也不過就是供過於求 200 萬桶而已。  
共享服務成為電動車發展推手   彭博新能源財經的較精確估算模型,基本構想是分別計算電動車的各主要零組件以及各種成本下降的情況,考量降價後消費者對電動車接受度的提升幅度,來預期電動車的普及速度,比較電動車與汽油車的維修成本、汽油成本,以及最重要的電池成本。目前電池成本佔電動車總製造成本約三分之一,而鋰電池成本正在快速下降,從過去每度電容量 1,000 美元以上,已經降至 400 美元以下,以彭博新能源財經預估的下降曲線,至 2030 年更有可能降至 100 美元上下。   另一方面則要考慮用電問題,若電動車真的如預期起飛,到 2040 年,將會年消耗 19 億度電力,相當於 2015 年全人類發電量的 10%。不過,電動車本身對電力系統也會有所幫助,電動車所用的電池,老化至容量剩 80% 時就必須汰換,但此時電池用來做為能源儲存用途還綽綽有餘,隨著電動車發展,二次使用的電池也將推動能源儲存,因而促進電網電力更有效的運用,也能推動風能、太陽能等潔淨能源的發展,而能補上電動車的電力需求。   但電池產量大增,不會因為原物料漲價而無法降價嗎?彭博新能源財經計算發現,到 2030 年,製造鋰電池所使用的鋰、鎳、錳、銅,也不過僅佔目前地球已知蘊藏量的 1% 而已,而到了 2030 年以後的新電池,則可能已經不是目前的鋰電池,而是未來的新電池技術,使用不同的原物料,打造更輕薄短小且更便宜的電池。   共享服務如 Uber 與 Lyft 也將成為電動車的推手,共乘機制讓汽車使用率提高,可能 1 年行駛里程數超過 2 萬英里,在如此高里程下,汽油車的維護成本將大為高於電動車,而電動車電池所省下來的汽油成本也將成正比增加,因而使得電池成本攤提下來相對更加便宜,因此彭博新能源財經推估,若是共享服務成功發展,將大為提升電動車市佔率,在 2040 年時達到新車出貨量的 5 成。   不過電動車是否會造成油價崩盤,還有許多變數,如儘管電動車本身成本降低,但是也要配合更多充電站建設才能促使消費者買單,此外。若是油價降至 20 美元且不再回升,低廉的油價本身就會促進石油需求,進而抵銷電動車所減少的汽油需求。但無論如何,電動車起飛只是開端,之後每年都會有更多電動車上路,取代傳統汽油車,而進一步持續減少石油在交通方面的需求,遲早有一天會讓石油走上末路。

(首圖來源: CC BY 2.0)    (本文授權轉載自《》─〈〉)

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

※廣告預算用在刀口上,網站設計公司幫您達到更多曝光效益

※自行創業 缺乏曝光? 下一步"網站設計"幫您第一時間規劃公司的門面形象

南投搬家前需注意的眉眉角角,別等搬了再說!

你真的會寫單測嗎?TDD初體驗

前言:

  昨天讀到了一篇文章,講的是TDD,即Test-Driven Development,測試驅動開發。大體意思是,它要求在編寫某個功能的代碼之前先編寫測試代碼,然後只編寫使測試通過的功能代碼,通過測試來推動整個開發的進行。這有助於編寫簡潔可用和高質量的代碼,並加速開發過程。

  初讀之時,瞬間感受到了震撼,感覺和自己之前的開發流程全都不一樣,之前是由始至終,而這種思想確實以終為始。後來一查這種思想早在前幾年甚至前幾十年就被提出了,進而被廣泛運用到了敏捷開發中。看來是自己孤落寡聞了,於是我準備將這種思想用到今後的開發中,要做的第一件事,就是溫習如何寫用例。

為什麼是溫習?

  早在實習的時候,我們研發組就有寫用例的習慣,但是隨着開發逐漸熟悉,這種習慣不知不覺就被丟棄了,有頁面的點點點,沒頁面的看邏輯。相信有很多人也像我一樣,不知不覺就把這項技能丟棄了,接下來就讓我們一起,去重新撿起這項技能。

工具選擇

Junit

對於一個Java開發工程師來說,一提到寫單測,我們最先想到的,一定是Junit。下面是maven坐標

<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.11</version>
    <scope>test</scope>
</dependency>

用Junit我們可以快速的,簡潔的用註解進行單元測試。

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:conf/core/*.xml")
public class ObjTest {

  @Test
  public void testFunc(){
     //todo test          
  }
}

這裏要注意的是@ContextConfiguration註解中的路徑是Spring配置文件的位置。測試的方法必須是public的,且沒有返回值。

mockito

mockito是一個用於模擬對象的工具,我認為他也是測試工作中必不可少的一部分,詳細的介紹我推薦可以看一下:

人生苦短,我用Mockito 

比較不錯的入門案例,它的maven坐標地址為:

<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-all</artifactId>
    <version>1.9.5</version>
    <scope>test</scope>
</dependency>

Mock這種測試方法, 對比傳統的Junit測試,有如下好處:

    1. 不用每次測試的是時候,都初始化Spring容器,採用Mock的方式模擬對象,效率高
    2. 對象間的依賴關係,可以用Mock去表達,同時,我們不關心的部分,我們都可以用Mock的方式代替(比如對象A引用對象B的某某方法,但是我們不關係對象B方法實現,只想藉助方法,這個時候就可以Mock)
    3. 可以應對複雜的測試環境,比如方法調用順序、方法調用次數等等。

以下是Mock的一個小案例:

@RunWith(MockitoJUnitRunner.class)
public class MockitoTest {
    /**
     * mock對象
     */
    @Mock
    List<String> mockedList;

    @Before
    public void setUp() {
        MockitoAnnotations.initMocks(this);
    }

    @Test
    public void testMock() {
        // mock對象行為
        Mockito.when(mockedList.get(0)).thenReturn("one");
        Assert.assertEquals("one", mockedList.get(0));
        // 僅僅是mock了對象的行為,實際上列表還是空的
        Assert.assertEquals(0, mockedList.size());

        //驗證mock對象的get方法被調用過,且調用時的參數是0
        Mockito.verify(mockedList).get(0);
    }
}

這裡在使用@Mock的時候,必須事先調用MockitoAnnotations.initMocks(this),且使用@RunWith(MockitoJUnitRunner.class)

Jacoco

JaCoCo是一個開源的覆蓋率工具,支持多種覆蓋率的統計,其中包括:

    1. 行覆蓋率:度量被測程序的每行代碼是否被執行,判斷標準行中是否至少有一個指令被執行。
    2. 類覆蓋率:度量計算class類文件是否被執行。
    3. 分支覆蓋率:度量if和switch語句的分支覆蓋情況,計算一個方法裏面的總分支數,確定執行和不執行的 分支數量。
    4. 方法覆蓋率:度量被測程序的方法執行情況,是否執行取決於方法中是否有至少一個指令被執行。
    5. 指令覆蓋:計數單元是單個java二進制代碼指令,指令覆蓋率提供了代碼是否被執行的信息,度量完全 獨立源碼格式。
    6. 圈複雜度:在(線性)組合中,計算在一個方法裏面所有可能路徑的最小數目,缺失的複雜度同樣表示測 試案例沒有完全覆蓋到這個模塊。

下面是它的maven坐標:

<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-all</artifactId>
    <version>1.9.5</version>
    <scope>test</scope>
</dependency>

接下來我們用maven插件的方式,對jacoco進行配置

<plugin>
     <groupId>org.jacoco</groupId>
      <artifactId>jacoco-maven-plugin</artifactId>
       <version>0.8.3</version>
       <configuration>
            <includes>
               <include>com/**/*</include>
            </includes>
            <!-- rules裏面指定覆蓋規則 -->
            <rules>
            <rule implementation="org.jacoco.maven.RuleConfiguration">
               <element>BUNDLE</element>
               <limits>  
               <!-- 指定方法覆蓋到50% -->
               <limit implementation="org.jacoco.report.check.Limit">
                   <counter>METHOD</counter>
                   <value>COVEREDRATIO</value>
                   <minimum>0.50</minimum>
                </limit>
                <!-- 指定分支覆蓋到50% -->
                <limit implementation="org.jacoco.report.check.Limit">
                    <counter>BRANCH</counter>
                    <value>COVEREDRATIO</value>
                    <minimum>0.50</minimum>
                 </limit>
                 <!-- 指定類覆蓋到100%,不能遺失任何類 -->
                 <limit implementation="org.jacoco.report.check.Limit">
                    <counter>CLASS</counter>
                    <value>MISSEDCOUNT</value>
                    <maximum>0</maximum>
                  </limit>
                  </limits>
              </rule>
              </rules>
         </configuration>
         <executions>
             <execution>
                <id>pre-test</id>
                  <goals>
                       <goal>prepare-agent</goal>
                   </goals>
             </execution>
             <execution>
                   <id>post-test</id>
                   <phase>test</phase>
                   <goals>
                       <goal>report</goal>
                   </goals>
             </execution>
       </executions>
  </plugin>

  這裏值得注意的是<include>com/**/*</include>指的是class文件的位置。做完這些以後,我們就可以生成報表了。因為我們是用maven插件的方式進行配置的,所以如果我們使用idea進行開發的時候,就可以看到右側maven一欄中出現了jacoco插件

 最常用的就是這兩個,一個是檢查配置是否正確,第二個是用來將exec文件,生成index.html用來進行觀察覆蓋率。

我們先執行maven中的test指令,這時,我們在target中就可以看到一個jacoco.exec文件。

有了這個jacoco.exec文件,就可以使用jacoco的report方法,來生成文件。

 右鍵index.html文件,選擇Reveal in Finder(Mac),windows也是類似,打開文件磁盤的位置。

 可以看到,由於這個項目之前沒有幾個單測,所以覆蓋率特別低。點開之後,就可以看到具體的代碼,非常的方便。

 最後今天配置jacoco的時候,踩了2個坑:

1 用idea進行開發的同學。使用jacoco的時候,不要勾選這個按鈕,它會跳過你測試階段的代碼執行,進而不會生成jacoco.exec文件。

 

 2 保證自己測試代碼沒有錯誤(尤其是項目中,由於代碼更新,測試用例沒有更新,導致的測試不可用)

這裏的現象是雖然可以生成jacoco.exec 文件,而且可以report成文檔,但是打開之後發現,代碼覆蓋率都是0。

最後:

希望大家都可以保持寫測試用例的好習慣,謝謝

 

 

 

 

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】

※帶您來了解什麼是 USB CONNECTOR  ?

※自行創業 缺乏曝光? 下一步"網站設計"幫您第一時間規劃公司的門面形象

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!!

※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

※廣告預算用在刀口上,網站設計公司幫您達到更多曝光效益

小白學 Python(22):time 和 calendar 模塊簡單使用

人生苦短,我選Python

前文傳送門

time 模塊

今天我們要介紹的是一個會經常用到的模塊—— time ,顧名思義,這是一個時間相關的模塊。前面我們也介紹過常用模塊,比如 os 模塊,在使用這些模塊前,我們需要先將它導入進來。 time 模塊的導入方式如下:

import time

先來一個簡單的樣例吧:

for i in range(0, 5):
    print(i)
    time.sleep(1)

打印結果我就不展示了,同學們應該都猜得到。那麼 time.sleep(1) 這句話的作用是什麼呢?

sleep() 方法是一個睡眠方法,意思就是程序執行到這裏,需要等待一會,什麼都不做,上面的代碼在執行的時候可以發現,每隔 1s 會打印一個数字, sleep() 裏面給出的參數是休眠的時間,單位是秒。

time 模塊的常用方法

首當其沖當然是獲取當前的時間戳。

print(time.time())

結果如下:

1573054874.6483195

這裏就看不懂了哇,我先來解釋下什麼是時間戳。

在程序中,一般已1970年1月1日0時0分0秒作為起始時間,時間戳就是從起始時間到現在的時長,在 Python 中,這個時長的單位是秒。那麼為什麼起始時間是1970年1月1日0時0分0秒呢?

emmmmmmmmmmmmm,這個我還真不知道,據我所了解的語言,所有的時間戳都是從這個時間點開始起算的。我順手幫各位同學百度了下,表示並沒有找到答案。

不要糾結這個問題了,我們看下一個。

print(time.localtime())

結果如下:

time.struct_time(tm_year=2019, tm_mon=11, tm_mday=6, tm_hour=23, tm_min=47, tm_sec=13, tm_wday=2, tm_yday=310, tm_isdst=0)

這個方法會給出詳細的當前的本地時間,可以細化到年、月、日、小時、分鐘、秒等。

注意: 這個時間是當前本地的計算的時間哦,如果修改計算機的時間,這個值會發生相應的改變的。

print(time.mktime(time.localtime()))

結果如下:

1573055380.0

各位同學看着打印結果應該已經猜到了, mktime() 可以將當前的本地時間轉化為一個時間戳。

以上不管是時間戳、還是本地時間,看起來並不方便,下面我們介紹如何格式化時間。

最簡單的方法,可以使用函數 asctime()

print(time.asctime(time.localtime()))

結果如下:

Wed Nov  6 23:53:52 2019

這個結果還帶着英文,並不符合中國人的習慣嘛,別急,我們還可以自定義格式。

print(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()))

結果如下:

2019-11-06 23:55:56

這樣看着就舒服多了么,我們可以通過 strftime() 來自定義日期格式。

這裏列舉一下日期格式化的符號:

  • %y 兩位數的年份表示(00-99)
  • %Y 四位數的年份表示(000-9999)
  • %m 月份(01-12)
  • %d 月內中的一天(0-31)
  • %H 24小時制小時數(0-23)
  • %I 12小時制小時數(01-12)
  • %M 分鐘數(00=59)
  • %S 秒(00-59)
  • %a 本地簡化星期名稱
  • %A 本地完整星期名稱
  • %b 本地簡化的月份名稱
  • %B 本地完整的月份名稱
  • %c 本地相應的日期表示和時間表示
  • %j 年內的一天(001-366)
  • %p 本地A.M.或P.M.的等價符
  • %U 一年中的星期數(00-53)星期天為星期的開始
  • %w 星期(0-6),星期天為星期的開始
  • %W 一年中的星期數(00-53)星期一為星期的開始
  • %x 本地相應的日期表示
  • %X 本地相應的時間表示
  • %Z 當前時區的名稱
  • %% %號本身

哇,這也太多了,記不住怎麼辦?

其實這個並不需要你都記下來,只需要記住常用的就好了,就比如我上面使用的年、月、日、時、分、秒。其餘的不常用的可以在有需要的時候再來查表。

有時候時間之間不使用短橫杠 - 來隔開,而選擇使用斜杠 / 隔開,這個怎麼辦?

這個很簡單咯,看我的:

print(time.strftime("%Y/%m/%d %H:%M:%S", time.localtime()))

結果如下:

2019/11/07 00:02:18

calendar 模塊

都聊到這裏了,我們順便再聊一個模塊,日曆。

先看下代碼演示吧,這個就比較有意思了:

import calendar

print(calendar.calendar(theyear=2020, w=2, l=1, c=6))

結果如下:

                                  2020

      January                   February                   March
Mo Tu We Th Fr Sa Su      Mo Tu We Th Fr Sa Su      Mo Tu We Th Fr Sa Su
       1  2  3  4  5                      1  2                         1
 6  7  8  9 10 11 12       3  4  5  6  7  8  9       2  3  4  5  6  7  8
13 14 15 16 17 18 19      10 11 12 13 14 15 16       9 10 11 12 13 14 15
20 21 22 23 24 25 26      17 18 19 20 21 22 23      16 17 18 19 20 21 22
27 28 29 30 31            24 25 26 27 28 29         23 24 25 26 27 28 29
                                                    30 31

       April                      May                       June
Mo Tu We Th Fr Sa Su      Mo Tu We Th Fr Sa Su      Mo Tu We Th Fr Sa Su
       1  2  3  4  5                   1  2  3       1  2  3  4  5  6  7
 6  7  8  9 10 11 12       4  5  6  7  8  9 10       8  9 10 11 12 13 14
13 14 15 16 17 18 19      11 12 13 14 15 16 17      15 16 17 18 19 20 21
20 21 22 23 24 25 26      18 19 20 21 22 23 24      22 23 24 25 26 27 28
27 28 29 30               25 26 27 28 29 30 31      29 30

        July                     August                  September
Mo Tu We Th Fr Sa Su      Mo Tu We Th Fr Sa Su      Mo Tu We Th Fr Sa Su
       1  2  3  4  5                      1  2          1  2  3  4  5  6
 6  7  8  9 10 11 12       3  4  5  6  7  8  9       7  8  9 10 11 12 13
13 14 15 16 17 18 19      10 11 12 13 14 15 16      14 15 16 17 18 19 20
20 21 22 23 24 25 26      17 18 19 20 21 22 23      21 22 23 24 25 26 27
27 28 29 30 31            24 25 26 27 28 29 30      28 29 30
                          31

      October                   November                  December
Mo Tu We Th Fr Sa Su      Mo Tu We Th Fr Sa Su      Mo Tu We Th Fr Sa Su
          1  2  3  4                         1          1  2  3  4  5  6
 5  6  7  8  9 10 11       2  3  4  5  6  7  8       7  8  9 10 11 12 13
12 13 14 15 16 17 18       9 10 11 12 13 14 15      14 15 16 17 18 19 20
19 20 21 22 23 24 25      16 17 18 19 20 21 22      21 22 23 24 25 26 27
26 27 28 29 30 31         23 24 25 26 27 28 29      28 29 30 31
                          30

我們把 2020 年的日曆打印出來了。

  • w = 每個日期之間的間隔字符數
  • l = 每周所佔用的行數
  • c = 每個月之間的間隔字符數

以後我們看日曆可以使用這個函數看了。

要用你們用,反正我是不用,我選擇使用這個:

除了直接返回全年的日曆,calendar 還支持返回指定月份的日曆:

print(calendar.month(2019, 11))

結果如下:

   November 2019
Mo Tu We Th Fr Sa Su
             1  2  3
 4  5  6  7  8  9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30

我們還可以直接獲得某月的總天數:

print(calendar.monthlen(2019, 11))

結果如下:

30

這個功能好像有點雞肋,我們獲取某月的天數難道不是都靠那句兒歌么?

一三五七八十臘,三十一天永不差

我們還可以知道指定的日期對應的星期數:

print(calendar.weekday(2019, 11, 7))

結果如下:

3

這個我覺得蠻實用的,再也不用自己寫算法去推算了。

示例代碼

本系列的所有代碼小編都會放在代碼管理倉庫 Github 和 Gitee 上,方便大家取用。

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

※廣告預算用在刀口上,網站設計公司幫您達到更多曝光效益

※自行創業 缺乏曝光? 下一步"網站設計"幫您第一時間規劃公司的門面形象

南投搬家前需注意的眉眉角角,別等搬了再說!