Java識別天際線並輸出到圖片中——Skyline

全部代碼已託管至GitHub
歡迎訪問~~

最終希望實現類似這樣的效果(圖片網上隨便找的,版權問題請聯繫我):
在這裏插入圖片描述

獲取天際線的流程大概是這樣:

1.讀取圖片,獲取rgb值存入數組
2.根據提取出藍色通道的值,並且繪製出直方圖
3.根據直方圖算出一個閾值threshold
4.把圖中所有藍色通道的值高於threshold的點全部染白(認爲是天空)
把圖中所有藍色通道的值低於threshold的點全部染黑(認爲是陸地)
5.從上往下遍歷圖片,保留第一個黑點,這樣將得到一條黑線,就是天際線
6.連接天際線中不連續的點,最終得到一條完整的天際線

大概解釋一下這個流程:
首先,我們對於每個像素pixel會得到一個rgb的值,比如(10,124,255)第三位是blue的值,這個值是在0-255之間的,那麼我們統計所有像素點的rgb中的blue的值, 會得到很多0-255的值,把這些圖繪製成一個直方圖,這個直方圖可能會有2個峯值,一個比較藍,一個比較不藍(好奇怪的表述。。),然後那個比較藍的大概就是天空的顏色,那個比較不藍的就是地面啦,那麼這兩個峯值中間的最小值就是我們所要的threshold了。
後面的部分好像都挺簡單的~

做到第四步大概是這樣的:
在這裏插入圖片描述

其中的關鍵點有:

  1. 第三部中計算threshold的時候, 要先算出直方圖的兩個peak峯值,然後在這兩個peak中間找到一個minimum value作爲threshold,否則可能threshold會出現在peak外的位置;
  2. 第6步中,我第一次寫的時候遇到了一個小坑,圖中做到第5步可能是下面這樣的情況:
    在這裏插入圖片描述
    這是還沒有連線的時候,看似有些x座標上是沒有黑點的,但其實每個x座標上都是有黑點的,只是他們可能在一些奇怪的位置,這些點我們可以認爲是無效點,這些點需要被我們忽略掉,然後得到一個離散的點圖,然後把離散的點圖之間用連線的方式連起來(這裏連線的方式我採用的是一個比較笨的方法,get兩個點,直接貪心遍歷周圍8個點去找最短距離作爲next step,然後把所有的next step連起來)

就這樣~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章