日本橡實歉收 熊出沒覓食上萬件5年來最多_網頁設計

台北網頁設計公司這麼多該如何選擇?

網動是一群專業、熱情、向前行的工作團隊,我們擁有靈活的組織與溝通的能力,能傾聽客戶聲音,激發創意的火花,呈現完美的作品

摘錄自2020年10月27日中央社報導

日本近期相繼傳出熊出沒於人類生活圈,今年4月到9月共目擊1萬3670件,是2016年以來最多的一年。日本政府分析,主因可能是橡實歉收,導致熊往人居處覓食。

※推薦評價好的iphone維修中心

擁有專業的維修技術團隊,同時聘請資深iphone手機維修專家,現場說明手機問題,快速修理,沒修好不收錢

過去熊出沒的高峰是從冬眠中醒來的5月到6月,但今年8月與9月的出沒件數也增加許多。日本讀賣新聞報導,近期各地發生多起民眾遭熊襲擊的事件,昨天(26日)政府召開相關會議討論因應對策。環境省表示,將要求各都道府縣,將加強共享熊出沒的資訊與聯繫,撤除放置在外的農作物與廚餘等。

生物多樣性
國際新聞
日本
處變不驚──與野生動物相遇

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

網頁設計最專業,超強功能平台可客製化

窩窩以「數位行銷」「品牌經營」「網站與應用程式」「印刷品設計」等四大主軸,為每一位客戶客製建立行銷脈絡及洞燭市場先機。

紐西蘭推動「國內木材優先」政策 將創造逾3000個工作機會_潭子電動車

※超省錢租車方案

商務出差、學生出遊、旅遊渡假、臨時用車!GO 神州租賃有限公司!合法經營、合法連鎖、合法租賃小客車!

摘錄自2020年5月7日大紀元報導

來自紐西蘭全國各地的商會和林業領袖呼籲政府採取「國內木材優先(wood-first )」的政策。該政策意味著,在新冠病毒(covid-19)之後,國產和加工木材將成為公共資助的住宅、商業和公共建築的首選建築材料。預計該政策可以在全國範圍內創造數千個就業機會,並減少紐西蘭林業對國際出口的依賴。

羅托魯瓦湖理事會(Rotorua Lakes Council)五年前通過了這一決策,它是第一個通過該政策的理事會。現在,羅托魯瓦(Rotorua)、陶朗加(Tauranga)、富東灣(Eastern Bay of Plenty)、奧克蘭和其他幾個商會呼籲中央政府也通過這一決策。Deloitte的研究顯示,建築用木材產品增加25%,將為全國各地的木材加工、林業和運輸行業以及港口創造逾3000個就業崗位,以及間接的支持性就業崗位。

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

有別於一般網頁架設公司,除了模組化的架站軟體,我們的營業主軸還包含:資料庫程式開發、網站建置、網頁設計、電子商務專案開發、系統整合、APP設計建置、專業網路行銷。

 

生活環境
建築
環境經濟
農林漁牧業
循環經濟
土地利用
國際新聞
紐西蘭
林業
國產材

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

※Google地圖已可更新顯示潭子電動車充電站設置地點!!

日本、大陸,發現這些先進的國家已經早就讓電動車優先上路,而且先進國家空氣品質相當好,電動車節能減碳可以減少空污

HTC Desire 21 pro 5G 正式推出!Desire 系列首款 5G 手機,搭載 6.7 吋 90Hz 螢幕與 5000mAh 大電池,早鳥限時優惠 11,990 元_如何寫文案

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

擁有後台管理系統的網站,將擁有強大的資料管理與更新功能,幫助您隨時新增網站的內容並節省網站開發的成本。

上週國外才有傳聞 HTC 即將推出新機,想不到 HTC 也相當迅速在今(13)日稍早正式發表 Deire 系列的首款 5G 手機「HTC Desire 21 pro 5G」,除了擁有完整的 5G 頻段覆蓋、搭載 6.7 吋 90Hz 更新率大螢幕、 4800 萬像素 AI 主相機和 5000mAh 大電量電池,滿足入門 5G 手機用戶對於螢幕體驗、生活拍攝記錄、長續航的使用需求。

HTC Desire 21 pro 5G 正式推出!Desire 系列首款 5G 手機,搭載 6.7 吋 90Hz 螢幕與 5000mAh 大電池,早鳥限時優惠 11,990 元

作為 HTC 在 2021 年推出的首款 5G 新機, HTC Desire 21 pro 5G 不僅提供完整的 5G 頻段(n1, n3, n5, n7, n28, n41, n78)、支援 5G+4G 雙卡雙待,更進一步優化 EN-DC 組合,使得 EN-DC 組合增加 30% 覆蓋面積更廣,同時支援 SA&NSA 雙模組網,讓用戶隨時隨地享受穩定的 5G 飆網速度。

HTC Desire 21 pro 5G 配備 6.7 吋 FHD+ 解析度的挖孔全螢幕,螢幕配備 90Hz 螢幕更新率和 120Hz 觸控採樣率,並支援 HDR10 影片播放,提供用戶流暢的使用體驗。另外,硬體規格則搭載高通 Snapdragon 690 5G 行動平台、配備 8GB RAM 和 128GB ROM ,內建 5000mAh 大電池和 QC 4.0+ 快速充電,能滿足全天候的長續航需求。

相機部份, HTC Desire 21 pro 5G 配備 4800 萬像素四鏡頭主相機(4800 萬像素主鏡頭+800 萬像素廣角 HDR 鏡頭、200 萬像素微距鏡頭以及 200 萬像素景深鏡頭)和 1600 萬像素前置自拍相機,前鏡頭及主鏡頭皆搭配最新的 AI 場景辨識功能。

銷售資訊

HTC Desire 21 pro 5G 推出 8GB RAM+128GB ROM 單一版本,並提供「星辰藍」與「幻境紫」兩種配色選擇,建議售價為新台幣 12,990 元。
銷售通路方面,即日起陸續於 HTC專賣店、HTC專櫃門市、HTC網路商店及全台經銷通路門市,以及PCHOME購物、MOMO購物、YAHOO購物商城、神腦線上、蝦皮購物、東森購物上市開賣。

更多關於 HTC Desire 21 pro 5G 產品與活動資訊:點我前往 HTC 官網

限時早鳥優惠 學生再享 10% 折扣

為歡慶 HTC Desire 21 pro 5G 上市,即日起至 2 月 28 日期間凡前往 HTC專賣店、HTC專櫃門市及HTC網路商店購買 HTC Desire 21 pro 5G ,除享上市早鳥優惠價新台幣 11,990 元,上網登錄更加贈「HTC馬卡龍真無線藍牙耳機-櫻花粉」(市價新台幣 999 元)。學生專有福利再加碼,HTC網路商店另提供校園專案,購買 HTC Desire 21 pro 5G 特享校園專案 10% 折扣優惠。

※教你寫出一流的銷售文案?

銷售文案是什麼?A文案是廣告用的文字。舉凡任何宣傳、行銷、販賣商品時所用到的文字都是文案。在網路時代,文案成為行銷中最重要的宣傳方式,好的文案可節省大量宣傳資源,達成行銷目的。

更多關於 HTC Desire 21 pro 5G 產品與活動資訊:點我前往 HTC 官網

圖片/消息來源:HTC

延伸閱讀:
爆料大神釋出 OPPO Find X3 Pro 首批高清晰官方渲染圖

OPPO Reno5 、Reno5 Pro 正式在台發表:全新升級 AI 錄影、獨家 Reno Glow 2.0 星鑽工藝打造精緻外觀

您也許會喜歡:

【推爆】終身$0月租 打電話只要1元/分

立達合法徵信社-讓您安心的選擇

※別再煩惱如何寫文案,掌握八大原則!

什麼是銷售文案服務?A就是幫你撰寫適合的廣告文案。當您需要販售商品、宣傳活動、建立個人品牌,撰寫廣告文案都是必須的工作。

msi 電競筆電全面升級,最新 Tiamat 強勢降臨_網頁設計公司

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

當全世界的人們隨著網路時代而改變向上時您還停留在『網站美醜不重要』的舊有思維嗎?機會是留給努力改變現況的人們,別再浪費一分一秒可以接觸商機的寶貴時間!

這回 msi 在 CES 2021 舉辦的發表會光是特效就非常驚人,適逢 msi 的 35 周年之際,整個高規格、大製作、大工程的鋪墊下,就是為了迎接本次全電競筆電陣容的更新與最新「眾神之母 Tiamat」的強勢降臨,接下來就一起看看到底這回端出哪些好菜來以饗玩家。

msi 電競筆電全面升級,最新 Tiamat 強勢降臨

整個發表會中,一開場就直接宣布 2021 年率先將旗下 GE、GS、GP、GF 系列電競筆電升級搭載甫發表的最新一代 Nvidia GeForce RTX 30 系列獨立顯卡,就由新世代顯示卡與筆電其他硬體、軟體調校完美搭配,能將系統效能完整釋放,為玩家帶來如同電影場景般的極致沉浸遊戲體驗。

GE76 Raider 系列與 GE76 Raider Dragon Edition Tiamat
在 GE76 Raider Dragon Edition Tiamat 的外殼上刻畫了象徵無窮力量的古老神獸。GE 系列採用炫彩華麗 Mystic Light 設計,最高搭載最新 Nvidia GeForce RTX 3080 獨立顯卡與第 11 代 Intel Core i9 處理器,採用最新Wi-Fi 6E 打造超高速連線速度。為確保筆電能在極致遊戲中依然維持穩定,GE 系列採用 Cooler Boost 5 散熱模組,強大雙風扇搭配 6 組熱導管,能帶來更多的氣流量以有效使筆電冷卻。

GS66 Stealth
GS66 Stealth 採用磨砂黑低調質感設計,為內心隱藏著熱血遊戲魂的商務人士提供了最完美的保護色,不論任何情境你都可以毫無違和感的隱身其中。現在,GS66 Stealth 領先升級搭載最新 GeForce RTX 30 系列獨立顯示卡, DLSS2.0將 AI 人工智慧技術運用在 GPU 的影像處理,能提供極致順暢的 4k 超高解析度畫面、即時光線追蹤以及 60FPS 以上近乎真實的遊戲畫面呈現。GS66 Stealth也將最新第 11 代 Intel 高達 8 核心處理器的高運算能力發揮到極致,提供更佳的遊戲效能表現。

GP66 / GP76 Leopard
全新 GP66 / GP76 Leopard 電競筆電,專為工程師繁複的程式工作打造,全新的外型設計更具低調質感,GP Leopard 系列展現比以往更加強大的效能。GP66 、 GP76 Leopard 最高搭載 GeForce RTX 3080 獨立顯卡,以及最新第 11 代 Intel Core  i7-10870H 處理器,展現極致的 8 核心運算處理能力。此外,全新配置的 I/O 連接埠能支援各種類型的資料傳輸,同時亦支援最高 8K 的顯示輸出,能在大尺寸螢幕上完整呈現細緻的畫面,是複雜的工程與設計專案工作的絕佳配備。

GF75 / 65 Thin系列
對於熱愛遊戲的玩家來說,纖薄設計的 GF75 / GF65 Thin 絕對是多數人推薦的遊戲配備首選。GF Thin 系列搭載最高第 11 代 Intel Core i7-10750H 處理器與 GeForce RTX 30 系列獨立顯示卡,最高 144Hz 更新率的 IPS 等級窄邊框面板設計,提供前所未有的速度感和視覺清晰度。

※想知道最厲害的網頁設計公司嚨底家"!

RWD(響應式網頁設計)是透過瀏覽器的解析度來判斷要給使用者看到的樣貌

Stealth 15M
發表會的另一個亮點是 msi 推出的這款世界最輕巧纖薄的 15 吋電競筆電 – Stealth 15M。源自於都會風格的靈感,Stealth 15M 重量僅 1.7kg,機身只有 16.15mm,纖薄機身中卻蘊藏著不妥協的效能。Stealth 15M 是全球首款搭載第 11代 Intel H 系列處理器的電競筆電,最大渦輪頻率 5GHz 頻率 。Stealth 15M 同時升級搭載 GeForce RTX 30 系列獨立顯卡,讓遊戲玩家能暢玩遊戲大作,也讓年輕的商務人士能輕鬆完成日常工作。

Creator 15
最後,msi 也率先為創意工作者量身打造絕佳的創作平台。Creator 15 是一款全能型的筆記型電腦,True Pixel 顯示技術包括 4K UHD 超高畫質解析度的面板,透過 True Color 校正技術調校出更精準的色彩,支援 100% AdobeRGB 廣色域提供更完整範圍顏色呈現,同時,True Pixel 技術也經過 CalMAN 專業色彩認證,提供最準確且真實的視覺呈現。透過最新的 GeForce RTX 30 系列獨立顯卡,能加快影片與 3D 動畫的渲染時間。此外,Creator 15 亦推出可觸控 FHD 面板的規格選擇,可多指觸控的面板讓您更輕鬆、更高效率地揮灑創意。透過螢幕更快速的滑動、縮放畫面,更加直覺性的的操作。99.9Whr 大容量電池能提供長時間的續航力,你只需要專注在創意工作,沒有後顧之憂。

MSI全新系列筆電 強勢登場 限時預購登錄送

本次發表會新品於 1/14 – 1/25 開放搶先預購,第一波將提供多達 11 款規格供消費者選擇,於 msi 官方商城、PChome 24h 購物、momo 購物網預購搭載 GeForce RTX 30 系列獨立顯卡之 msi 電競筆電,上網登錄即可獲得「城市襲擊者電競後背包」( 市價NT$3,899 ) 乙個,數量有限,兌換完畢為止。
【活動詳情,點這裡】

您也許會喜歡:

【推爆】終身$0月租 打電話只要1元/分

立達合法徵信社-讓您安心的選擇

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

透過資料庫的網站架設建置,建立公司的形象或購物系統,並提供最人性化的使用介面,讓使用者能即時接收到相關的資訊

ASUS ZenBook、VivoBook、Chromebook、ExpertBook多款筆電亮相,ProArt 外接螢幕延伸你的工作台_網頁設計

※推薦評價好的iphone維修中心

擁有專業的維修技術團隊,同時聘請資深iphone手機維修專家,現場說明手機問題,快速修理,沒修好不收錢

除了專為遊戲玩家們打造的 ROG 新品,這回 Asus 本家品牌的筆電們也一口氣多機型傾巢而出,其中包含甫於去年推出的雙螢幕筆電在今年也有新品推出,還有各式輕薄筆電與為專業工作打造的 ProArt 產品,都對過去的自己有所突破,看起來 Asus  2021 年新品項將會相當精彩。

ASUS ZenBook、VivoBook 、Chromebook、ExpertBook多款筆電亮相,ProArt 外接螢幕延伸你的工作台

Asus ZenBook Pro Duo 15 OLED / Pro Duo 14
在今年新的 Pro Duo 雙螢幕系列兩款產品的更新,最顯著的就是招牌雙螢幕為了能夠讓使用時更順手,將位於鍵盤上方的副螢幕設計改為下方採用極輕薄短小的轉軸來幫助螢幕的活動,當你掀開筆電時自動抬起 7 – 9.5 度的結構,讓主螢幕與副螢幕、鍵盤之間呈現 147 度角,視覺上有如一體,清晰無死角,下方所預留的空間也讓散熱通道更流暢。

Pro Duo 15 OLED 配備雙 4K 顯示器,OLED 主螢幕可支援 HDR,色域覆蓋 DCI-P3 100%。配備 Intel Core i9  8 核心處理器、最新 Nvidia GrForce RTX 顯卡,記憶體與儲存容量最大可達 32GB DDR4 與 1TB PCIe 3.0 SSD。在機身上配置有 2 個 Thunderbolt 連接埠可支援 2 個外接 4K 顯示器,且支援高速 Wi-Fi 6 無線網路連接,另外還配有 1 個最新的 HDMI 2.1 連接埠。至於小老弟 Pro Duo 14,擁有 14 吋 FHD 觸控螢幕,色域可覆蓋 100% sRGB,搭載第 11 代 Intel Core i7 處理器,內部配置 MX450 / Iris Xe 顯卡。Duo 系列兩款新品皆配備有 70Wh 電池,可提供最長達 17 小時的續航力。

Asus VivoBook S14 
以輕薄隨身行動力為主打的 VivoBook 系列這回也端出新品,以更輕、更小、更纖薄的體型將占比達 90% 的四面窄邊框 14 吋顯示器放入其中,重量僅有 1.3 Kg。搭載第 11 代 Intel Core 處理器與 Iris Xe 顯卡,通過最新 Intel Evo 認證, 最長續航可達 17 小時,支援 Thunderbolt 4 與 Wi-Fi 6 高速有線與無線連接。

Chromebook Flip CX5
如果你對 Chromebook 的印象還停留在最早為預算有限者或是學生、教育用途而設,那你可得更新一下了。由於 Chrome OS 的高自由度與 Google Play Store 中的大量資源,成為越來越多人的選擇之一。這次新推出 Flip CX5 就是一款專為消費者市場打造的產品。外型輕薄簡約,ErgoLift 轉軸可供其 15.6 吋、81% 佔比的三邊窄邊框螢幕  360 度翻轉。

在硬體配備方面,Flip CX5 最高可配第 11 代 Intel Core i7 處理器、Intel Iris Xe 顯卡、16GB記憶體與 512GB SSD,最長續航力可達到 12 小時。機身上設置有 2 個 USB-C 3.2 Gen 2 可支援快速充電, HDMI 2.0 連接埠則可以供你外接一部 4K 60Hz 顯示器。這款 Chromebook 通過美國軍規 MIL-STD 810H 認證,對於較為嚴峻的環境具有相當大的抵抗力。

ExpertBook B9400CEAV
號稱全球最輕 14 吋商務筆電的 ExpertBook B9400CEAV ,從專設的鏡頭蓋與軟硬體等方面對安全性的強化就能看出這款機型專為差旅人士所設計,擁有非常輕薄的外型,鎂合金外殼經過多道工藝精雕細琢,重量僅有 880g 至 1kg 左右 ,但卻是通過美國軍規 MIL-STD 810H 的認證的硬朗身骨,轉軸的開闔耐用度更比普通比電高出 150%。在 13 吋的機身上配備 14 吋 FHD 顯示器,極窄邊框設計讓它的螢幕佔比來到 94%,並且可覆蓋 100% sRGB 色域。

網頁設計最專業,超強功能平台可客製化

窩窩以「數位行銷」「品牌經營」「網站與應用程式」「印刷品設計」等四大主軸,為每一位客戶客製建立行銷脈絡及洞燭市場先機。

這款筆電配備第 11 代 Intel Core 處理器、32GB 記憶體與最高 2TB 儲存容量,如果你有重度的資料儲存需求,內部的雙儲存設能幫助你將它升級至最高 4TB。ExpertBook B9400CEAV 通過 Intel 最新的 Evo 認證,擁有一秒喚醒、長續航、快充、快速回饋、高速連接等多方面能力。在電池配置上有兩種規格,33Whr 機種最長續航可達 9.5 小時,66Whr 機種最長續航可達 20.7 小時。

ProArt Display PA148CTV
這款專為多螢幕使用而設計的 14 吋 IPS 觸控型螢幕重量只有 740g,可支援 10 點觸控,並且覆蓋 100% sRGB 色域,在機身上配置了豐富的連接埠以適配於這種外接需求。機身後方配置了可調整 15 度至 75 度的腳架,讓用戶以最舒適、順手的方式調節使用。用戶可以自訂軟體熱鍵與面板樣貌進行快速切換控制,作為主螢幕延伸出去的另一個工作台。

機身後方配置了一個 Asus Dial 轉輪,支援 Adobe、Microsoft 等軟體的快捷鍵的使用,還能自行定義它的每一個動作按鈕,快速旋轉選擇與呼叫,讓工作流程更簡易流暢。

您也許會喜歡:

【推爆】終身$0月租 打電話只要1元/分

立達合法徵信社-讓您安心的選擇

台北網頁設計公司這麼多該如何選擇?

網動是一群專業、熱情、向前行的工作團隊,我們擁有靈活的組織與溝通的能力,能傾聽客戶聲音,激發創意的火花,呈現完美的作品

好尷尬!Samsung 官方被發現用 iPhone 發推特來宣傳 Unpacked 發表會活動_租車

※超省錢租車方案

商務出差、學生出遊、旅遊渡假、臨時用車!GO 神州租賃有限公司!合法經營、合法連鎖、合法租賃小客車!

用別牌的手機來貼文推廣另一個品牌活動,這種低級失誤雖然不是第一次發生,但之前大多都是代言人居多,沒想到已經有這麼多先例之後,最近即將舉辦 Unpacked 發表會的 Smasung,稍早美國官方 Twitter 小編又不小心犯了這個錯誤,使用 iPhone 來預告 Unpacked 發表會的內容,雖然推文很快被刪除,但已經有人把圖給擷取下來。

Samsung 官方被發現用 iPhone 發推特來宣傳 Unpacked 發表會活動

Samsung 今年重要的 Unpacked 發表會即將於今日稍晚時間登場,預計會推出 Galaxy S21 系列,也因此各國的官方 Twitter、FaceBook 粉絲團都開始醞釀,稍早 Samsung Mobile US 官方 Twitter 刊登一則「隨著 #SamsungUnpacked 越來越近,我們正努力為您帶來令人振奮的消息,您希望看到哪些創新與進步呢?」貼文時,右下角使用的裝置寫著 iPhone,不是自家 Samsung,這畫面很快就引起熱烈討論,也被人快速截圖下來:

雖然這無關大雅,但畢竟是 Samsung 官方推特帳號,推文內容又是今年重點新機的發表會,還是讓人覺得不太應該,只能說小編可能當時真的累了!不過從另一面來說,也為 Samsung 這場發表會製造出不小的話題。

這其實也不是 Samsung 第一次傳出這類新聞,不過之前都是代言人,像 2013 年網球明星 David Ferrer 就曾用 iPhone 貼文 Galaxy S4 的內容,另外還有前 T-Mobile 執行長 John Legere 用 iPhone 說他很喜歡 Note 3:

Samsung 也曾在 2 年前,起訴俄羅斯品牌大使 Ksenia Sobchak 在某次電視採訪中被發現使用 iPhone X,而不是 Samsung 手機:

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

有別於一般網頁架設公司,除了模組化的架站軟體,我們的營業主軸還包含:資料庫程式開發、網站建置、網頁設計、電子商務專案開發、系統整合、APP設計建置、專業網路行銷。

所以說,管理手機品牌的小編,在發推文時真的要多加注意,不確定美國這位 Samsung Mobile US 小編會不會受到相關懲處。

資料來源:Apple Insider

多位 Samsung Galaxy S20 FE 國外用戶反應螢幕有問題,出現奇怪現象,連外媒都碰到

您也許會喜歡:

【推爆】終身$0月租 打電話只要1元/分

立達合法徵信社-讓您安心的選擇

※Google地圖已可更新顯示潭子電動車充電站設置地點!!

日本、大陸,發現這些先進的國家已經早就讓電動車優先上路,而且先進國家空氣品質相當好,電動車節能減碳可以減少空污

3. OpenCV-Python——圖像梯度算法、邊緣檢測、圖像金字塔與輪廓檢測與傅里恭弘=叶 恭弘變換_如何寫文案

※別再煩惱如何寫文案,掌握八大原則!

什麼是銷售文案服務?A就是幫你撰寫適合的廣告文案。當您需要販售商品、宣傳活動、建立個人品牌,撰寫廣告文案都是必須的工作。

一、圖像梯度算法

1、圖像梯度-Sobel算子

 

 dst = cv2.Sobel(src, ddepth, dx, dy, ksize)

  • ddepth:圖像的深度
  • dx和dy分別表示水平和豎直方向
  • ksize是Sobel算子的大小
 1 # *******************圖像梯度算法**********************開始
 2 import cv2
 3 # import numpy as np
 4 
 5 img = cv2.imread('pie.png',cv2.IMREAD_GRAYSCALE)
 6 cv2.imshow("img",img)
 7 cv2.waitKey()
 8 cv2.destroyAllWindows()
 9 
10 # 显示圖像函數
11 def cv_show(img,name):
12     cv2.imshow(name,img)
13     cv2.waitKey()
14     cv2.destroyAllWindows()
15 
16 # Sobel算子——x軸
17 sobelx = cv2.Sobel(img,cv2.CV_64F,1,0,ksize=3)   # 計算水平的
18 cv_show(sobelx,'sobelx')
19 
20 # 白到黑是正數,黑到白就是負數了,所有的負數會被截斷成0,所以要取絕對值
21 sobelx = cv2.Sobel(img,cv2.CV_64F,1,0,ksize=3)
22 sobelx = cv2.convertScaleAbs(sobelx)             # 取絕對值
23 cv_show(sobelx,'sobelx')
24 
25 # Sobel算子——y軸
26 sobely = cv2.Sobel(img,cv2.CV_64F,0,1,ksize=3)
27 sobely = cv2.convertScaleAbs(sobely)             # 取絕對值
28 cv_show(sobely,'sobely')
29 
30 # 求和
31 sobelxy = cv2.addWeighted(sobelx,0.5,sobely,0.5,0)  # 按權重計算
32 cv_show(sobelxy,'sobelxy')
33 
34 # 也有直接計算xy軸的————不推薦使用
35 # sobelxy=cv2.Sobel(img,cv2.CV_64F,1,1,ksize=3)
36 # sobelxy = cv2.convertScaleAbs(sobelxy)
37 # cv_show(sobelxy,'sobelxy')
38 # *******************圖像梯度算法**********************結束

用lena圖像來實際操作一下:

 1 # *******************圖像梯度算法-實際操作**********************開始
 2 import cv2
 3 
 4 # 显示圖像函數
 5 def cv_show(img,name):
 6     cv2.imshow(name,img)
 7     cv2.waitKey()
 8     cv2.destroyAllWindows()
 9 
10 img = cv2.imread('lena.jpg',cv2.IMREAD_GRAYSCALE)
11 cv_show(img,'img')
12 
13 # 分別計算x和y
14 img = cv2.imread('lena.jpg',cv2.IMREAD_GRAYSCALE)
15 sobelx = cv2.Sobel(img,cv2.CV_64F,1,0,ksize=3)
16 sobelx = cv2.convertScaleAbs(sobelx)
17 sobely = cv2.Sobel(img,cv2.CV_64F,0,1,ksize=3)
18 sobely = cv2.convertScaleAbs(sobely)
19 sobelxy = cv2.addWeighted(sobelx,0.5,sobely,0.5,0)
20 cv_show(sobelxy,'sobelxy')
21 # *******************圖像梯度算法-實際操作**********************結束

      

2、圖像梯度-Scharr和Laplacian算子

(1)Scharr算子

(2)Laplacian算子

(3)不同算子之間的差距

 1 # *******************圖像梯度算子-Scharr+laplacian**********************開始
 2 import cv2
 3 import numpy as np
 4 
 5 #不同算子的差異
 6 img = cv2.imread('lena.jpg',cv2.IMREAD_GRAYSCALE)
 7 sobelx = cv2.Sobel(img,cv2.CV_64F,1,0,ksize=3)
 8 sobely = cv2.Sobel(img,cv2.CV_64F,0,1,ksize=3)
 9 sobelx = cv2.convertScaleAbs(sobelx)
10 sobely = cv2.convertScaleAbs(sobely)
11 sobelxy =  cv2.addWeighted(sobelx,0.5,sobely,0.5,0)
12 
13 scharrx = cv2.Scharr(img,cv2.CV_64F,1,0)
14 scharry = cv2.Scharr(img,cv2.CV_64F,0,1)
15 scharrx = cv2.convertScaleAbs(scharrx)
16 scharry = cv2.convertScaleAbs(scharry)
17 scharrxy =  cv2.addWeighted(scharrx,0.5,scharry,0.5,0)
18 
19 laplacian = cv2.Laplacian(img,cv2.CV_64F)
20 laplacian = cv2.convertScaleAbs(laplacian)
21 
22 res = np.hstack((sobelxy,scharrxy,laplacian))
23 
24 # 显示圖像函數
25 def cv_show(img,name):
26     cv2.imshow(name,img)
27     cv2.waitKey()
28     cv2.destroyAllWindows()
29 cv_show(res,'res')
30 # *******************圖像梯度算子-Scharr+laplacian**********************結束

二、邊緣檢測

Canny邊緣檢測

  • 1) 使用高斯濾波器,以平滑圖像,濾除噪聲。

  • 2) 計算圖像中每個像素點的梯度強度和方向。

  • 3) 應用非極大值(Non-Maximum Suppression)抑制,以消除邊緣檢測帶來的雜散響應。

  • 4) 應用雙閾值(Double-Threshold)檢測來確定真實的和潛在的邊緣。

  • 5) 通過抑制孤立的弱邊緣最終完成邊緣檢測。

1、高斯濾波器

2、梯度和方向

3、非極大值抑制

4、雙閾值檢測

 1 # *******************邊緣檢測**********************開始
 2 import cv2
 3 import numpy as np
 4 
 5 img=cv2.imread("lena.jpg",cv2.IMREAD_GRAYSCALE)
 6 
 7 v1=cv2.Canny(img,80,150)  # 設置雙閾值 最小和最大
 8 v2=cv2.Canny(img,50,100)
 9 
10 res = np.hstack((v1,v2))
11 
12 # 显示圖像函數
13 def cv_show(img,name):
14     cv2.imshow(name,img)
15     cv2.waitKey()
16     cv2.destroyAllWindows()
17 cv_show(res,'res')
18 # *******************邊緣檢測**********************結束

三、圖像金字塔

1、高斯金字塔

(1)高斯金字塔:向下採樣方法(縮小)

(2)高斯金字塔:向上採樣方法(放大)

※教你寫出一流的銷售文案?

銷售文案是什麼?A文案是廣告用的文字。舉凡任何宣傳、行銷、販賣商品時所用到的文字都是文案。在網路時代,文案成為行銷中最重要的宣傳方式,好的文案可節省大量宣傳資源,達成行銷目的。

  

 1 # *******************圖像金字塔--高斯金字塔**********************開始
 2 import cv2
 3 import numpy as np
 4 
 5 # 显示圖像函數
 6 def cv_show(img,name):
 7     cv2.imshow(name,img)
 8     cv2.waitKey()
 9     cv2.destroyAllWindows()
10 
11 img=cv2.imread("AM.png")
12 # cv_show(img,'img')
13 print (img.shape)
14 
15 # 高斯金字塔-上採樣 (可執行多次)
16 up=cv2.pyrUp(img)
17 # cv_show(up,'up')
18 print (up.shape)
19 
20 # 高斯金字塔-下採樣 (可執行多次)
21 down=cv2.pyrDown(img)
22 # cv_show(down,'down')
23 print (down.shape)
24 
25 # 高斯金字塔-先上採樣再下採樣 (會損失信息-變模糊)
26 up=cv2.pyrUp(img)
27 up_down=cv2.pyrDown(up)
28 # cv_show(up_down,'up_down')
29 cv_show(np.hstack((img,up_down)),'up_down')
30 # *******************圖像金字塔--高斯金字塔**********************結束

2、拉普拉斯金字塔

 1 # *******************圖像金字塔-拉普拉斯金字塔**********************開始
 2 import cv2
 3 import numpy as np
 4 
 5 # 显示圖像函數
 6 def cv_show(img,name):
 7     cv2.imshow(name,img)
 8     cv2.waitKey()
 9     cv2.destroyAllWindows()
10 
11 img=cv2.imread("AM.png")
12 down=cv2.pyrDown(img)
13 down_up=cv2.pyrUp(down)
14 l_1=img-down_up
15 cv_show(l_1,'l_1')
16 # *******************圖像金字塔-拉普拉斯金字塔**********************結束

四、圖像輪廓

 cv2.findContours(img,mode,method)

  mode:輪廓檢索模式

  • RETR_EXTERNAL :只檢索最外面的輪廓;
  • RETR_LIST:檢索所有的輪廓,並將其保存到一條鏈表當中;
  • RETR_CCOMP:檢索所有的輪廓,並將他們組織為兩層:頂層是各部分的外部邊界,第二層是空洞的邊界;
  • RETR_TREE:檢索所有的輪廓,並重構嵌套輪廓的整個層次;

  method:輪廓逼近方法

  • CHAIN_APPROX_NONE:以Freeman鏈碼的方式輸出輪廓,所有其他方法輸出多邊形(頂點的序列)。
  • CHAIN_APPROX_SIMPLE:壓縮水平的、垂直的和斜的部分,也就是,函數只保留他們的終點部分。

為提高準確性,使用二值圖像。

1、輪廓檢測及繪製

 1 # *******************圖像輪廓**********************開始
 2 import cv2
 3 import numpy as np
 4 
 5 # 讀入圖像轉換為二值圖像
 6 img = cv2.imread('contours.png')
 7 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)     # 轉換為灰度圖
 8 ret, thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)  # 轉換成二值圖
 9 
10 # 显示圖像函數
11 def cv_show(img,name):
12     cv2.imshow(name,img)
13     cv2.waitKey()
14     cv2.destroyAllWindows()
15 # cv_show(thresh,'thresh')
16 
17 # 輪廓檢測  第一個就是二值的結果  第二個是一堆輪廓點  第三個是層級
18 binary, contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
19 
20 # 繪製輪廓
21 draw_img = img.copy()  # 注意需要copy,要不原圖會變。。。
22 res = cv2.drawContours(draw_img, contours, -1, (0, 0, 255), 2) # 傳入繪製圖像,輪廓,輪廓索引(-1全部),顏色模式,線條厚度
23 # cv_show(res,'res')
24 
25 draw_img = img.copy()
26 res = cv2.drawContours(draw_img, contours, 2, (0, 0, 255), 2)
27 cv_show(res,'res')
28 # *******************圖像輪廓**********************結束

2、輪廓特徵

 1 import cv2
 2 
 3 # 讀入圖像轉換為二值圖像
 4 img = cv2.imread('contours.png')
 5 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)     # 轉換為灰度圖
 6 ret, thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)  # 轉換成二值圖
 7 
 8 # 輪廓檢測  第一個就是二值的結果  第二個是一堆輪廓點  第三個是層級
 9 binary, contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
10 
11 # 繪製輪廓
12 draw_img = img.copy()
13 res = cv2.drawContours(draw_img, contours, 2, (0, 0, 255), 2)
14 
15 # 輪廓特徵
16 cnt = contours[0]               # 獲取輪廓
17 print(cv2.contourArea(cnt))     # 計算面積
18 print(cv2.arcLength(cnt, True)) # 計算周長,True表示閉合的

3、輪廓近似

     

 1 import cv2
 2 
 3 img = cv2.imread('contours2.png')
 4 # 显示圖像函數
 5 def cv_show(img,name):
 6     cv2.imshow(name,img)
 7     cv2.waitKey()
 8     cv2.destroyAllWindows()
 9 
10 # 二值+輪廓檢測
11 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
12 ret, thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
13 binary, contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
14 cnt = contours[0]
15 # 輪廓繪製
16 draw_img = img.copy()
17 res = cv2.drawContours(draw_img, [cnt], -1, (0, 0, 255), 2)
18 # cv_show(res,'res')
19 
20 # 輪廓近似
21 epsilon = 0.05*cv2.arcLength(cnt,True)
22 approx = cv2.approxPolyDP(cnt,epsilon,True)
23 
24 draw_img = img.copy()
25 res = cv2.drawContours(draw_img, [approx], -1, (0, 0, 255), 2)
26 cv_show(res,'res')

(1)邊界矩形

 1 # *******************圖像輪廓-邊界矩形**********************開始
 2 import cv2
 3 
 4 # 显示圖像函數
 5 def cv_show(img,name):
 6     cv2.imshow(name,img)
 7     cv2.waitKey()
 8     cv2.destroyAllWindows()
 9 
10 img = cv2.imread('contours.png')
11 
12 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
13 ret, thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
14 binary, contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
15 cnt = contours[0]
16 
17 # 邊界矩形
18 x,y,w,h = cv2.boundingRect(cnt)
19 img = cv2.rectangle(img,(x,y),(x+w,y+h),(0,255,0),2)
20 cv_show(img,'img')
21 # 輪廓面積與邊界矩形比
22 area = cv2.contourArea(cnt)
23 x, y, w, h = cv2.boundingRect(cnt)
24 rect_area = w * h
25 extent = float(area) / rect_area
26 print ('輪廓面積與邊界矩形比',extent)
27 # *******************圖像輪廓-邊界矩形**********************結束

(2)外接圓

1 # 外接圓
2 (x,y),radius = cv2.minEnclosingCircle(cnt)
3 center = (int(x),int(y))
4 radius = int(radius)
5 img = cv2.circle(img,center,radius,(0,255,0),2)
6 cv_show(img,'img')

 五、傅里恭弘=叶 恭弘變換

  https://zhuanlan.zhihu.com/p/19763358

1、傅里恭弘=叶 恭弘的作用

  • 高頻:變化劇烈的灰度分量,例如邊界

  • 低頻:變化緩慢的灰度分量,例如一片大海

2、濾波

  • 低通濾波器:只保留低頻,會使得圖像模糊

  • 高通濾波器:只保留高頻,會使得圖像細節增強

  opencv中主要就是cv2.dft()和cv2.idft(),輸入圖像需要先轉換成np.float32 格式,得到的結果中頻率為0的部分會在左上角,通常要轉換到中心位置,通過shift變換。

3、傅里恭弘=叶 恭弘變換

 1 # *******************傅里恭弘=叶 恭弘變換**********************開始
 2 import numpy as np
 3 import cv2
 4 from matplotlib import pyplot as plt
 5 
 6 img = cv2.imread('lena.jpg',0)
 7 
 8 img_float32 = np.float32(img)
 9 
10 # 傅里恭弘=叶 恭弘變換
11 dft = cv2.dft(img_float32, flags = cv2.DFT_COMPLEX_OUTPUT)
12 dft_shift = np.fft.fftshift(dft)                            # 低頻值移動到中間
13 
14 # 對兩通道進行轉換——映射公式
15 magnitude_spectrum = 20*np.log(cv2.magnitude(dft_shift[:,:,0],dft_shift[:,:,1]))
16 
17 plt.subplot(121),plt.imshow(img, cmap = 'gray')
18 plt.title('Input Image'), plt.xticks([]), plt.yticks([])
19 plt.subplot(122),plt.imshow(magnitude_spectrum, cmap = 'gray')
20 plt.title('Magnitude Spectrum'), plt.xticks([]), plt.yticks([])
21 plt.show()
22 # *******************傅里恭弘=叶 恭弘變換**********************結束

4、高通、低通濾波器

低通濾波器:

 1 # *******************低通濾波器**********************開始
 2 import numpy as np
 3 import cv2
 4 from matplotlib import pyplot as plt
 5 
 6 img = cv2.imread('lena.jpg',0)
 7 
 8 img_float32 = np.float32(img)
 9 
10 # 傅里恭弘=叶 恭弘變換
11 dft = cv2.dft(img_float32, flags = cv2.DFT_COMPLEX_OUTPUT)
12 dft_shift = np.fft.fftshift(dft)
13 
14 rows, cols = img.shape
15 crow, ccol = int(rows/2) , int(cols/2)     # 中心位置
16 
17 # 低通濾波
18 mask = np.zeros((rows, cols, 2), np.uint8)  # 掩碼
19 mask[crow-30:crow+30, ccol-30:ccol+30] = 1  # 區域
20 
21 # IDFT
22 fshift = dft_shift*mask                     # 掩碼結合
23 f_ishift = np.fft.ifftshift(fshift)         # 位置還原
24 img_back = cv2.idft(f_ishift)               # 傅里恭弘=叶 恭弘逆變換
25 img_back = cv2.magnitude(img_back[:,:,0],img_back[:,:,1]) # 圖像轉換
26 
27 plt.subplot(121),plt.imshow(img, cmap = 'gray')
28 plt.title('Input Image'), plt.xticks([]), plt.yticks([])
29 plt.subplot(122),plt.imshow(img_back, cmap = 'gray')
30 plt.title('Result'), plt.xticks([]), plt.yticks([])
31 
32 plt.show()
33 # *******************低通濾波器**********************結束

高通濾波器:

 1 # *******************高通濾波器**********************開始
 2 import numpy as np
 3 import cv2
 4 from matplotlib import pyplot as plt
 5 
 6 img = cv2.imread('lena.jpg',0)
 7 
 8 img_float32 = np.float32(img)
 9 
10 dft = cv2.dft(img_float32, flags = cv2.DFT_COMPLEX_OUTPUT)
11 dft_shift = np.fft.fftshift(dft)
12 
13 rows, cols = img.shape
14 crow, ccol = int(rows/2) , int(cols/2)     # 中心位置
15 
16 # 高通濾波
17 mask = np.ones((rows, cols, 2), np.uint8)  # 掩碼
18 mask[crow-30:crow+30, ccol-30:ccol+30] = 0
19 
20 # IDFT
21 fshift = dft_shift*mask
22 f_ishift = np.fft.ifftshift(fshift)
23 img_back = cv2.idft(f_ishift)
24 img_back = cv2.magnitude(img_back[:,:,0],img_back[:,:,1])
25 
26 plt.subplot(121),plt.imshow(img, cmap = 'gray')
27 plt.title('Input Image'), plt.xticks([]), plt.yticks([])
28 plt.subplot(122),plt.imshow(img_back, cmap = 'gray')
29 plt.title('Result'), plt.xticks([]), plt.yticks([])
30 
31 plt.show()
32 # *******************高通濾波器**********************結束

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

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

擁有後台管理系統的網站,將擁有強大的資料管理與更新功能,幫助您隨時新增網站的內容並節省網站開發的成本。

曹工說Spring Boot源碼(29)– Spring 解決循環依賴為什麼使用三級緩存,而不是二級緩存_網頁設計公司_網頁設計公司

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

當全世界的人們隨著網路時代而改變向上時您還停留在『網站美醜不重要』的舊有思維嗎?機會是留給努力改變現況的人們,別再浪費一分一秒可以接觸商機的寶貴時間!

寫在前面的話

相關背景及資源:

曹工說Spring Boot源碼(1)– Bean Definition到底是什麼,附spring思維導圖分享

曹工說Spring Boot源碼(2)– Bean Definition到底是什麼,咱們對著接口,逐個方法講解

曹工說Spring Boot源碼(3)– 手動註冊Bean Definition不比遊戲好玩嗎,我們來試一下

曹工說Spring Boot源碼(4)– 我是怎麼自定義ApplicationContext,從json文件讀取bean definition的?

曹工說Spring Boot源碼(5)– 怎麼從properties文件讀取bean

曹工說Spring Boot源碼(6)– Spring怎麼從xml文件裡解析bean的

曹工說Spring Boot源碼(7)– Spring解析xml文件,到底從中得到了什麼(上)

曹工說Spring Boot源碼(8)– Spring解析xml文件,到底從中得到了什麼(util命名空間)

曹工說Spring Boot源碼(9)– Spring解析xml文件,到底從中得到了什麼(context命名空間上)

曹工說Spring Boot源碼(10)– Spring解析xml文件,到底從中得到了什麼(context:annotation-config 解析)

曹工說Spring Boot源碼(11)– context:component-scan,你真的會用嗎(這次來說說它的奇技淫巧)

曹工說Spring Boot源碼(12)– Spring解析xml文件,到底從中得到了什麼(context:component-scan完整解析)

曹工說Spring Boot源碼(13)– AspectJ的運行時織入(Load-Time-Weaving),基本內容是講清楚了(附源碼)

曹工說Spring Boot源碼(14)– AspectJ的Load-Time-Weaving的兩種實現方式細細講解,以及怎麼和Spring Instrumentation集成

曹工說Spring Boot源碼(15)– Spring從xml文件裡到底得到了什麼(context:load-time-weaver 完整解析)

曹工說Spring Boot源碼(16)– Spring從xml文件裡到底得到了什麼(aop:config完整解析【上】)

曹工說Spring Boot源碼(17)– Spring從xml文件裡到底得到了什麼(aop:config完整解析【中】)

曹工說Spring Boot源碼(18)– Spring AOP源碼分析三部曲,終於快講完了(aop:config完整解析【下】)

曹工說Spring Boot源碼(19)– Spring 帶給我們的工具利器,創建代理不用愁(ProxyFactory)

曹工說Spring Boot源碼(20)– 碼網恢恢,疏而不漏,如何記錄Spring RedisTemplate每次操作日誌

曹工說Spring Boot源碼(21)– 為了讓大家理解Spring Aop利器ProxyFactory,我已經拼了

曹工說Spring Boot源碼(22)– 你說我Spring Aop依賴AspectJ,我依賴它什麼了

曹工說Spring Boot源碼(23)– ASM又立功了,Spring原來是這麼遞歸獲取註解的元註解的

曹工說Spring Boot源碼(24)– Spring註解掃描的瑞士軍刀,asm技術實戰(上)

曹工說Spring Boot源碼(25)– Spring註解掃描的瑞士軍刀,ASM + Java Instrumentation,順便提提Jar包破解

曹工說Spring Boot源碼(26)– 學習字節碼也太難了,實在不能忍受了,寫了個小小的字節碼執行引擎

曹工說Spring Boot源碼(27)– Spring的component-scan,光是include-filter屬性的各種配置方式,就夠玩半天了

曹工說Spring Boot源碼(28)– Spring的component-scan機制,讓你自己來進行簡單實現,怎麼辦

工程代碼地址思維導圖地址

工程結構圖:

什麼是三級緩存

在獲取單例bean的時候,會進入以下方法:

org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String, boolean)
    
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
                // 1
		Object singletonObject = this.singletonObjects.get(beanName);
		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
			synchronized (this.singletonObjects) {
                                // 2
				singletonObject = this.earlySingletonObjects.get(beanName);
				if (singletonObject == null && allowEarlyReference) {
                                        // 3
					ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
					if (singletonFactory != null) {
                                                // 4
						singletonObject = singletonFactory.getObject();
						this.earlySingletonObjects.put(beanName, singletonObject);
						this.singletonFactories.remove(beanName);
					}
				}
			}
		}
		return singletonObject;
	}

這裏面涉及到了該類中的三個field。

	/** 1級緩存 Cache of singleton objects: bean name to bean instance. */
	private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

	/** 2級緩存 Cache of early singleton objects: bean name to bean instance. */
	private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);

	/** 3級緩存 Cache of singleton factories: bean name to ObjectFactory. */
	private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

接著說前面的代碼。

  • 1處,在最上層的緩存singletonObjects中,獲取單例bean,這裏面拿到的bean,直接可以使用;如果沒取到,則進入2處

  • 2處,在2級緩存earlySingletonObjects中,查找bean;

  • 3處,如果在2級緩存中,還是沒找到,則在3級緩存中查找對應的工廠對象,利用拿到的工廠對象(工廠對像中,有3個field,一個是beanName,一個是RootBeanDefinition ,一個是已經創建好的,但還沒有註入屬性的bean),去獲取包裝後的bean,或者說,代理後的bean。

    什麼是已經創建好的,但沒有註入屬性的bean?

    比如一個bean,有10個字段,你new了之後,對像已經有了,內存空間已經開闢了,堆裡已經分配了該對象的空間了,只是此時的10個field還是null。

ioc容器,普通循環依賴,一級緩存夠用嗎

說實話,如果簡單寫寫的話,一級緩存都沒問題。給大家看一個我以前寫的渣渣ioc容器:

曹工說Tomcat4:利用Digester 手擼一個輕量的Spring IOC容器

@Data
public class BeanDefinitionRegistry {
    /**
     * map:存儲 bean的class-》bean實例
     */
    private Map<Class, Object> beanMapByClass = new ConcurrentHashMap<>();
    
    /**
     * 根據bean 定義獲取bean
     * 1、先查bean容器,查到則返回
     * 2、生成bean,放進容器(此時,依賴還沒注入,主要是解決循環依賴問題)
     * 3、注入依賴
     *
     * @param beanDefiniton
     * @return
     */
    private Object getBean(MyBeanDefiniton beanDefiniton) {
        Class<?> beanClazz = beanDefiniton.getBeanClazz();
        Object bean = beanMapByClass.get(beanClazz);
        if (bean != null) {
            return bean;
        }
		// 0
        bean = generateBeanInstance(beanClazz);


        // 1 先行暴露,解決循環依賴問題
        beanMapByClass.put(beanClazz, bean);
        beanMapByName.put(beanDefiniton.getBeanName(), bean);

        // 2 查找依賴
        List<Field> dependencysByField = beanDefiniton.getDependencysByField();
        if (dependencysByField == null) {
            return bean;
        }
		
        // 3
        for (Field field : dependencysByField) {
            try {
                autowireField(beanClazz, bean, field);
            } catch (Exception e) {
                throw new RuntimeException(beanClazz.getName() + " 創建失敗",e);
            }
        }

        return bean;
    }
}

大家看上面的代碼,我只定義了一個field,就是一個map,存放bean的class-》bean。

    /**
     * map:存儲 bean的class-》bean實例
     */
    private Map<Class, Object> beanMapByClass = new ConcurrentHashMap<>();
  • 0處,生成bean,直接就是new
  • 1處,先把這個不完整的bean,放進map
  • 2處,獲取需要注入的屬性集合
  • 3處,進行自動注入,就是根據field的Class,去map裡查找對應的bean,設置到field裡。

上面這個代碼,有啥問題沒?spring為啥整整三級?

ioc,一級緩存有什麼問題

一級緩存的問題在於,就1個map,裏面既有完整的已經ready的bean,也有不完整的,尚未設置field的bean。

如果這時候,有其他線程去這個map裡獲取bean來用怎麼辦?拿到的bean,不完整,怎麼辦呢?屬性都是null,直接空指針了。

所以,我們就要加一個map,這個map,用來存放那種不完整的bean。這裏,還是拿spring舉例。我們可以只用下面這兩層:

	/** 1級緩存 Cache of singleton objects: bean name to bean instance. */
	private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

	/** 2級緩存 Cache of early singleton objects: bean name to bean instance. */
	private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);

因為spring代碼裡是三級緩存,所以我們對源碼做一點修改。

修改spring源碼,只使用二級緩存

修改創建bean的代碼,不放入第三級緩存,只放入第二級緩存

創建了bean之後,屬性注入之前,將創建出來的不完整bean,放到earlySingletonObjects

這個代碼,在org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean,我這邊只有4.0版本的spring源碼工程,不過這套邏輯,算是spring核心邏輯,和5.x版本差別不大。

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) {
		BeanWrapper instanceWrapper = null;
		if (mbd.isSingleton()) {
			instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
		}
		if (instanceWrapper == null) {
            // 1
			instanceWrapper = createBeanInstance(beanName, mbd, args);
		}
		final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
		Class beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null);
		...
		boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
				isSingletonCurrentlyInCreation(beanName));
		if (earlySingletonExposure) {
            // 2
			earlySingletonObjects.put(beanName,bean);
			registeredSingletonObjects.add(beanName);
			// 3
//			addSingletonFactory(beanName, new ObjectFactory() {
//				public Object getObject() throws BeansException {
//					return getEarlyBeanReference(beanName, mbd, bean);
//				}
//			});
		}
  • 1處,就是創建對象,就是new
  • 2處,這是我加的代碼,放入二級緩存
  • 3處,本來這就是增加三級緩存的位置,被我註釋了。現在,就不會往三級緩存放東西了

修改獲取bean的代碼,只從第一、第二級緩存獲取,不從第三級獲取

org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String, boolean)

之前的代碼是文章開頭那樣的,我這裏修改為:

	protected Object getSingleton(String beanName, boolean allowEarlyReference) {
		Object singletonObject = this.singletonObjects.get(beanName);
		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
			synchronized (this.singletonObjects) {
				singletonObject = this.earlySingletonObjects.get(beanName);
				return singletonObject;
			}
		}
		return (singletonObject != NULL_OBJECT ? singletonObject : null);

這樣,就是只用兩級緩存了。

兩級緩存,有啥問題?

ioc循環依賴,一點問題都沒有,完全夠用了。

我這邊一個簡單的例子,


public class Chick{
    private Egg egg;

    public Egg getEgg() {
        return egg;
    }

    public void setEgg(Egg egg) {
        this.egg = egg;
    }
}

public class Egg {
    private Chick chick;

    public Chick getChick() {
        return chick;
    }

    public void setChick(Chick chick) {
        this.chick = chick;
    }
    <bean id="chick" class="foo.Chick" lazy-init="true">
        <property name="egg" ref="egg"/>
    </bean>
    <bean id="egg" class="foo.Egg" lazy-init="true">
        <property name="chick" ref="chick"/>
    </bean>
        ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(
                "context-namespace-test-aop.xml");

        Egg egg = (Egg) ctx.getBean(Egg.class);

結論:

所以,一級緩存都能解決的問題,二級當然更沒問題。

但是,如果我這裏給上面的Egg類,加個切面(aop的邏輯,意思就是最終會生成Egg的一個動態代理對象),那還有問題沒?

    <aop:config>
        <aop:pointcut id="mypointcut" expression="execution(public * foo.Egg.*(..))"/>
        <aop:aspect id="myAspect" ref="performenceAspect">
            <aop:after method="afterIncubate" pointcut-ref="mypointcut"/>
        </aop:aspect>
    </aop:config>

注意這裏的切點:

execution(public * foo.Egg.*(..))

就是切Egg類的方法。

加了這個邏輯後,我們繼續運行,在 Egg egg = (Egg) ctx.getBean(Egg.class);行,會拋出如下異常:

我塗掉了一部分,因為那是官方對這個異常的推論,因為我們改了代碼,所以推論不準確,因此乾脆隱去。

這個異常是說:

兄弟啊,bean egg已經被注入到了其他bean:chick中。(因為我們循環依賴了),但是,注入到chick中的,是Egg類型。但是,我們這裏最後對egg這個bean,進行了後置處理,生成了代理對象。那其他bean裡,用原始的bean,是不是不太對啊?

所以,spring給我們拋錯了。

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

透過資料庫的網站架設建置,建立公司的形象或購物系統,並提供最人性化的使用介面,讓使用者能即時接收到相關的資訊

怎麼理解呢?以io流舉例,我們一開始都是用的原始字節流,然後給別人用的也是字節流,但是,最後,我感覺不方便,我自己悄悄弄了個緩存字符流(類比代理對象) ,我是方便了,但是,別人用的,還是原始的字節流啊。

你bean不是單例嗎?不能這麼玩吧?

所以,這就是二級緩存,不能解決的問題。

什麼問題?aop情形下,注入到其他bean的,不是最終的代理對象。

三級緩存,怎麼解決這個問題

要解決這個問題,必須在其他bean(chick),來查找我們(以上面例子為例,我們是egg)的時候,查找到最終形態的egg,即代理後的egg。

怎麼做到這點呢?

加個三級緩存,裏面不存具體的bean,裏面存一個工廠對象。通過工廠對象,是可以拿到最終形態的代理後的egg。

ok,我們將前面修改的代碼還原:

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) {
		BeanWrapper instanceWrapper = null;
		if (mbd.isSingleton()) {
			instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
		}
		if (instanceWrapper == null) {
            // 1
			instanceWrapper = createBeanInstance(beanName, mbd, args);
		}
		final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
		Class beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null);

		boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
				isSingletonCurrentlyInCreation(beanName));
		if (earlySingletonExposure) {
            // 2
//			Map<String, Object> earlySingletonObjects = this.getEarlySingletonObjects();
//			earlySingletonObjects.put(beanName,bean);
//
//			Set<String> registeredSingletonObjects = this.getRegisteredSingletonObjects();
//			registeredSingletonObjects.add(beanName);
			
            // 3
			addSingletonFactory(beanName, new ObjectFactory() {
				public Object getObject() throws BeansException {
					return getEarlyBeanReference(beanName, mbd, bean);
				}
			});
		}
  • 1處,創建bean,單純new,不注入

  • 2處,revert我們的代碼

  • 3處,這裏new了一個ObjectFactory,然後會存入到如下的第三級緩存。

    	/** 3級緩存 Cache of singleton factories: bean name to ObjectFactory. */
    	private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
    

    注意,new一個匿名內部類(假設這個匿名類叫AA)的對象,其中用到的外部類的變量,都會在AA中隱式生成對應的field。

    大家看上圖,裏面的3個字段,和下面代碼1處中的,幾個字段,是一一對應的。

    			addSingletonFactory(beanName, new ObjectFactory() {
    				public Object getObject() throws BeansException {
                        // 1
    					return getEarlyBeanReference(beanName, mbd, bean);
    				}
    			});
    

ok,現在,egg已經把自己存進去了,存在了第三級緩存,1級和2級都沒有,那後續chick在使用getSingleton查找egg的時候,就會進入下面的邏輯了(就是文章開頭的那段代碼,下面已經把我們的修改還原了):

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
//		Object singletonObject = this.singletonObjects.get(beanName);
//		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
//			synchronized (this.singletonObjects) {
//				singletonObject = this.earlySingletonObjects.get(beanName);
//				return singletonObject;
//			}
//		}
//		return (singletonObject != NULL_OBJECT ? singletonObject : null);

		Object singletonObject = this.singletonObjects.get(beanName);
		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
			synchronized (this.singletonObjects) {
				singletonObject = this.earlySingletonObjects.get(beanName);
				if (singletonObject == null && allowEarlyReference) {
					ObjectFactory singletonFactory = this.singletonFactories.get(beanName);
					if (singletonFactory != null) {
                        // 1
						singletonObject = singletonFactory.getObject();
						this.earlySingletonObjects.put(beanName, singletonObject);
						this.singletonFactories.remove(beanName);
					}
				}
			}
		}
		return (singletonObject != NULL_OBJECT ? singletonObject : null);
	}

上面就會進入1處,調用singletonFactory.getObject();

而前面我們知道,這個factory的邏輯是:

			addSingletonFactory(beanName, new ObjectFactory() {
				public Object getObject() throws BeansException {
                    // 1
					return getEarlyBeanReference(beanName, mbd, bean);
				}
			});

1處就是這個工廠方法的邏輯,這裏面,簡單說,就會去調用各個beanPostProcessor的getEarlyBeanReference方法。

其中,主要就是aop的主力beanPostProcessor,AbstractAutoProxyCreator#getEarlyBeanReference

其實現如下:

	public Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
		Object cacheKey = getCacheKey(bean.getClass(), beanName);
		this.earlyProxyReferences.add(cacheKey);
        // 1
		return wrapIfNecessary(bean, beanName, cacheKey);
	}

這裏的1處,就會去對egg這個bean,創建代理,此時,返回的對象,就是個代理對象了,那,注入到chick的,自然也是代理後的egg了。

關於SmartInstantiationAwareBeanPostProcessor

我們上面說的那個getEarlyBeanReference就在這個接口中。

這個接口繼承了BeanPostProcessor

而創建代理對象,目前就是在如下兩個方法中去創建:

public interface BeanPostProcessor {
    Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
    
	Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;    
}

這兩個方法,都是在實例化之後,創建代理。那我們前面創建代理,是在依賴解析過程中:

public interface SmartInstantiationAwareBeanPostProcessor extends InstantiationAwareBeanPostProcessor {
    ...
	Object getEarlyBeanReference(Object bean, String beanName) throws BeansException;
}

所以,spring希望我們,在這幾處,要返回同樣的對象,即:既然你這幾處都要返回代理對象,那就不能返回不一樣的代理對象。

那我們再看看,到底,AbstractAutoProxyCreator有沒有遵守約定呢,這幾個方法裡,有沒有去返回同樣的代理包裝對象呢?

getEarlyBeanReference

	public Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
		Object cacheKey = getCacheKey(bean.getClass(), beanName);
        // 1
		this.earlyProxyReferences.add(cacheKey);
		return wrapIfNecessary(bean, beanName, cacheKey);
	}

1處,往field:

private final Set<Object> earlyProxyReferences =
      Collections.newSetFromMap(new ConcurrentHashMap<Object, Boolean>(16));

裡,加了個cachekey,這個cachekey,主要也就是如下的字符串,用來唯一標識而已。

	protected Object getCacheKey(Class<?> beanClass, String beanName) {
		return beanClass.getName() + "_" + beanName;
	}

我們可以看看這個field在哪裡被用到了。

也就兩處,一處就是當前位置;另外一處,下面講。

這裏,主要就是看看到底要不要生成代理對象,要的話,就生成,不要就算了,另外,做了個標記:在earlyProxyReferences加了當前bean的key,表示:當前bean,已經被getEarlyBeanReference方法處理過了。

至於,最終到底有沒有生成代理對象,另說。畢竟調用wrapIfNecessary也不是說,一定就滿足切面,要生成代理對象。

可能返回的仍然是原始對象。

postProcessBeforeInitialization

public Object postProcessBeforeInitialization(Object bean, String beanName) {
   return bean;
}

這一處,沒做處理。

postProcessAfterInitialization

public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		if (bean != null) {
			Object cacheKey = getCacheKey(bean.getClass(), beanName);
            // 1
			if (!this.earlyProxyReferences.contains(cacheKey)) {
				return wrapIfNecessary(bean, beanName, cacheKey);
			}
		}
		return bean;
	}

這裏,1處這個判斷哈,就用到了前面我們說的那個field。那個field,只在兩處用,一處就是調用getEarlyBeanReference,會往裡面把當前bean的key放進去;另外一處,就是這裏。

這裏判斷,如果field裡不包含當前bean,就去調用wrapIfNecessary;如果包含(意味著,getEarlyBeanReference處理過了),就不調用了。

這裏,說到底,就是保證了,wrapIfNecessary只被調用一次。

看吧,wrapIfNecessary也就這兩處被調用了。

所以,我們可以得出結論,在aop這個beanPostProcessor中,有多處機會可以返回一個proxy對象,但是,最終,只要在其中一處處理了,其他處,根本不再繼續處理。

另外,還有一點很重要,在這個aop beanPostProcessor中,傳入了原始的bean,我們會去判斷,是否要給它創建代理,如果要,就創建;如果不要則:

返回原始對象

整個流程串起來

上面這個後置處理器看明白了,接下來,再看看創建bean的核心流程:

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) {
		// 1 
		BeanWrapper instanceWrapper = createBeanInstance(beanName, mbd, args);
		final Object bean = instanceWrapper.getWrappedInstance();
		
		if (earlySingletonExposure) {
            // 2
			addSingletonFactory(beanName, new ObjectFactory() {
				@Override
				public Object getObject() throws BeansException {
					return getEarlyBeanReference(beanName, mbd, bean);
				}
			});
		}

		// 3 
		Object exposedObject = bean;
    	// 4
        populateBean(beanName, mbd, instanceWrapper);
		
    	// 5
        if (exposedObject != null) {
            exposedObject = initializeBean(beanName, exposedObject, mbd);
        }

		if (earlySingletonExposure) {
            // 6
			Object earlySingletonReference = getSingleton(beanName, false);
            
			if (earlySingletonReference != null) {
                // 7
				if (exposedObject == bean) {
					exposedObject = earlySingletonReference;
				}
				else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
                    // 8
                    ...
				}
			}
		}

		return exposedObject;
	}

上面流程中,做了部分刪減。但基本創建一個bean,就這幾步了。

  • 1處,創建bean對象,此時,屬性什麼的全是null,可以理解為,只是new了,field還沒設置

  • 2處,添加到第三級緩存;加進去的,只是個factory,只有循環依賴的時候,才會發揮作用

  • 3處,把原始bean,存到exposedObject

  • 4處,填充屬性;循環依賴情況下,A/B循環依賴。假設當前為A,那麼此時填充A的屬性的時候,會去:

    new B;

    填充B的field,發現field裡有一個是A類型,然後就去getBean(“A”),然後走到第三級緩存,拿到了A的ObjectFactory,然後調用ObjectFactory,然後調用AOP的後置處理器類:getEarlyBeanReference,拿到代理後的bean(假設此處切面滿足,要創建代理);

    經過上面的步驟後,B裏面,field已經填充ok,其中,且填充的field是代理後的A,這裏命名為proxy A。

    B 繼續其他的後續處理。

    B處理完成後,被填充到當前的origin A(原始A)的field中

  • 5處,對A進行後置處理,此時調用aop後置處理器的,postProcessAfterInitialization;前面我們說了,此時不會再去調用wrapIfNecessary,所以這裏直接返回原始A,即origin A

  • 6處,去緩存裡獲取A,拿到的A,是proxy A

  • 7處,我們梳理下:

    exposedObject:origin A

    bean:原始A

    earlySingletonReference: proxy A

    此時,下面這個條件是滿足的,所以,exposedObject,最終被替換為proxy A:

    if (exposedObject == bean) {
        exposedObject = earlySingletonReference;
    }
    

源碼

文章用到的aop循環依賴的demo,自己寫一個也可以,很簡單:

https://gitee.com/ckl111/spring-boot-first-version-learn/tree/master/all-demo-in-spring-learning/spring-aop-xml-demo-cycle-reference

不錯的參考資料

https://blog.csdn.net/f641385712/article/details/92801300

總結

如果有問題,歡迎指出;歡迎加群討論;有幫助的話,請點個贊吧,謝謝

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

※想知道最厲害的網頁設計公司嚨底家"!

RWD(響應式網頁設計)是透過瀏覽器的解析度來判斷要給使用者看到的樣貌

小米手錶超值版在台推出:1.4吋彩色螢幕、5 ATM防水、9天長續航,售價 1,495 元將於 1/19 10:00 在台開賣_如何寫文案

※教你寫出一流的銷售文案?

銷售文案是什麼?A文案是廣告用的文字。舉凡任何宣傳、行銷、販賣商品時所用到的文字都是文案。在網路時代,文案成為行銷中最重要的宣傳方式,好的文案可節省大量宣傳資源,達成行銷目的。

在上個月小米手錶超值版(Mi Watch Lite)才在小米全球官網現身,想不到很快就在今(15)日由小米台灣宣布將在 1 月 19 日上午 10 點開賣啦!小米手錶超值版採用 1.4 吋彩色螢幕、支持 5 ATM 防水、內建多款錶手錶錶盤、GPS/GLONASS 定位、心率/睡眠監測以及 9 天的長續航,售價只要新台幣 1,495 元。

小米手錶超值版在台推出:1.4吋彩色螢幕、5ATM防水、9天長續航,售價 1,495 元將於 1/19 10:00 在台開賣

除了輕便、適合運動使用的小米手環系列,今日稍早小米台灣宣布將在 19 日在台灣開賣「小米手錶超值版」這款同樣兼具輕巧特色的智慧穿戴裝置。小米手錶超值版推出米白色、藍色以及黑色三種顏色手錶錶殼、五種錶帶顏色選擇。

另外,小米手錶超值版內建多款主題錶盤和錶盤功能定制,用戶能搭配出自我的獨特風格:

螢幕方面,小米手錶超值版採用 1.4 吋 TFT 20*320 解析度的 LCD 彩色觸控螢幕,支援自動亮度調節功能。

支援 5ATM 防水機能(防水深度可達 50 公尺),運動模式則支援包括戶外跑步、室內跑步、戶外騎行、室內單車,自由活動、健走、越野、登山、泳池游泳、開放水域游泳以及板球共 11 種運動模式選擇。

小米手錶超值版搭載 GPS+GLONASS 定位和多種智慧感應器,讓手錶可精準記錄使用者的行蹤、速度、距離和消耗熱量。同時還能測量心率變化,掌握每次的運動狀態。

小米手錶超值版配備心律感應器,可 24 小時全天候準確測監測心率:

用戶可藉由睡眠監測功能記錄完整的睡眠數據,進而分析睡眠品質、有效保持良好睡眠習慣:

面對日常生活的壓力,小米手錶超值版也內建呼吸訓練功能,可引導使用者進行呼吸練習、減輕壓力:

所有在小米手錶超值版每天的心率、運動和睡眠數據,都能透過專屬 App 快速檢視:

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

擁有後台管理系統的網站,將擁有強大的資料管理與更新功能,幫助您隨時新增網站的內容並節省網站開發的成本。

小米手錶超值版內建 230mAh 電池,可在 2 小時充滿 100%電量。續航部分,小米手錶 Lite 一般使用情境可支持 9 天的使用續航,在開啟連續 GPS 運動模式則可使用 10 小時。

其他應用功能部分,小米手錶 Lite 除了能顯示來電通知、訊息、以及 App 提醒,也能直接控制手機多媒體播放和音量調整。

面對長時間工作,小米手錶超值版也支持久坐提醒的貼心功能:

價格方面,小米手錶超值版建議手價為新台幣 1,495 元,將於 1 月 19 日上午 10 點起正式開賣。

圖片/消息來源:小米台灣

延伸閱讀:
小米智慧攝影機雲台版2K 在台開賣:升級 2K 高畫質和 F1.4 大光圈,售價 1,095元

小米摺疊螢幕手機工程機曝光!再次於地鐵車廂被捕獲,只是螢幕摺痕有點顯眼

您也許會喜歡:

【推爆】終身$0月租 打電話只要1元/分

立達合法徵信社-讓您安心的選擇

※別再煩惱如何寫文案,掌握八大原則!

什麼是銷售文案服務?A就是幫你撰寫適合的廣告文案。當您需要販售商品、宣傳活動、建立個人品牌,撰寫廣告文案都是必須的工作。

國外 YouTube 頻道實測 PS5 vs 電腦 120FPS 模式的遊戲效能表現,GTX 1060 就贏過 PS5_網頁設計公司

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

當全世界的人們隨著網路時代而改變向上時您還停留在『網站美醜不重要』的舊有思維嗎?機會是留給努力改變現況的人們,別再浪費一分一秒可以接觸商機的寶貴時間!

PlayStation 5 顯示效能非常強大,這點相信很多人都知道,Sony 也曾透露最高能支援到 120FPS,這數字可說相當吸引遊戲玩家,而先前也有外媒實測確實有一些 PS5 遊戲可跑到 120FPS。為此近日就有國外 YouTube 頻道想到一個還蠻有趣的比較主題,如果以相同約 500 美金的電腦跟 PS5 相比,一樣的遊戲運行 120FPS,哪些顯示卡可以跟 PS5 表現一樣?結果沒想到四年前的 NVIDIA GTX 1060 就能擊敗 PS5。

國外 YouTuber 實測 PS5 vs 電腦 120FPS 模式的遊戲效能表現

開始介紹前也先說明一下,這位 YouTuber 的 PS5 vs PC 比較是以 120FPS 為前提,因此並不代表 PS5 效能這麼差,畢竟 PS5 都能運行 4K 遊戲,甚至未來還能支援到 8K,再加上 5.5 GB/s 客製化 NVME SSD,很多地方是這次測試表現不出來。

以下是先前外媒 PushSquare 分享 PS5 可運行 120FPS 的遊戲清單:

  • Borderlands 3 (PS5)
  • Call of Duty: Black Ops Cold War (PS5)
  • Destiny 2 (PS5)
  • Devil May Cry 5: Special Edition (PS5)
  • DIRT 5 (PS5)
  • Monster Boy and the Cursed Kingdom (PS5)
  • The Nioh Collection (PS5)
  • Tom Clancy’s Rainbow Six: Siege (PS5)

Gamers Nexus 就拿 Borderlands 3、Devil May Cry 5: Special Edition 與 DIRT 5 這三款遊戲進行測試。而畫質部分都是運行 1080p,品質設定基本上一模一樣,甚至把 PS5 的光追技術關掉。

首先是 Devil May Cry 5: Special Edition,這款遊戲幾乎不需要使用到 CPU 的效能,因此他們選擇 R3 3300X 就夠了,甚至還可以再往更低階挑,不過以 400~500 美金為前提,這顆跟 PS5 最接近。

下方是 PC 端的畫質設定:

顯示卡部分他們測試過 GTX 1070,會比 PS5 還要好,也因此降一級改用 GTX 1060 就差不多,測試時把光追關掉:

跑分結果,PC 部分平均可跑到 142.1 FPS,但 PS5 只能到 108.7 FPS:

DIRT 5 這款遊戲顯卡要用到 GTX 1080 才比較接近 PS5,不過以平均 FPS 來說,PS5 就以 119FPS 小勝 PC 的 108.9FPS:

※想知道最厲害的網頁設計公司嚨底家"!

RWD(響應式網頁設計)是透過瀏覽器的解析度來判斷要給使用者看到的樣貌

PS5 與 PC 同一畫面的比較圖:

最後是 Borderlands 3,這款遊戲需要用到 GTX 1070 Ti 才跟 PS5 最接近,PC 以平均 130.3FPS 表現勝過 PS5 的 118.9FPS:

同一畫面比較圖:

有些人可能會覺得,測試這似乎沒什麼意義,事實上還是有一個可以總結的答案,就是以高 FPS 的畫面表現來說,遊戲機表現不會比 PC 還出色,因此如果你是看中這一點想買 PS5 的人,PC 會是你更好的選擇。

說實在 PS5 vs PC 本來就很難相提並論,畢竟 PC 還能做很多事情,像是文書、繪圖等等,非常多功能,而 PS5 則可以讓玩家無需擔心遊戲不順暢狀況,進而提供最佳體驗。

完整影片:

IKEA 開始提供 PS5 與 Xbox Series X 的紙模型,讓你買家具之前可以快速比對

您也許會喜歡:

【推爆】終身$0月租 打電話只要1元/分

立達合法徵信社-讓您安心的選擇

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

透過資料庫的網站架設建置,建立公司的形象或購物系統,並提供最人性化的使用介面,讓使用者能即時接收到相關的資訊