題圖 | 視覺中國
我們有時候會聽到這麼一個詞--「蒙太奇」,但卻不知道這個詞是什麼意思。蒙太奇原為建築學術語,意為構成、裝配。而後又延伸為一種剪輯理論:當不同鏡頭拼接在一起時,往往又會產生各個鏡頭單獨存在時所不具有的特定含義。
這就是我們經常聽到了蒙太奇手法,在電影《飛屋環遊記》中皮克斯運用蒙太奇手法,用一個不到5分鐘的短片展現了主角的大半人生,感動無數觀眾。下面我們就看看今天的內容同蒙太奇有何關係。
效果展示
說這麼多都是虛的,下面我們看看實現的效果,到底什麼是蒙太奇馬賽克圖片,這裡用小松菜奈的照片作為測試:
原圖效果圖對比
最左邊的是蒙太奇圖縮小的效果,第二個則是正常大小顯示的效果,第三張是原圖,第四張是截取的某個區域的細節。從圖四可以很容易看出,我們的蒙太奇圖片是使用許多不同的圖片拼接而成的。
代碼實現
程序的實現分為幾個步驟,首先我們需要準備工作,一個是我們的底圖,也就是上面的圖三。另外就是需要一個圖片集,這個圖片集的選取有幾個規範,首先不能有gif圖和png圖片,其次就是圖片的顏色儘量豐富,圖片數量也多一些,這樣效果會更好。另外就是選取長寬比接近1的圖片效果會更好。然後就是我們代碼部分的工作了:
圖片預處理獲取顏色的主色調列表遍歷底圖的每個像素塊在色調列表中尋找與當前色調塊最相近的圖片將圖片修改大小後粘貼到當前遍歷的色調塊保存圖片大家對於上面的步驟或許還有些疑問,這些疑問在具體實現中細說。先看看我們要用到的一些模塊:
import osimport cv2import mathimport numpy as np其中opencv的安裝如下:
pip install opencv-python
3.1、圖片預處理
人工挑圖片還是比較麻煩的,所以我們只要求人先挑好一些圖片,然後我們將不符合規範的圖片刪除即可:
def renameImages(path)://獲取圖片路徑列表filelist = [path + i for i in os.listdir(path)]//用數字給圖片命名img_num = str(len(filelist))name = int(math.pow(10, len(img_num)))//遍歷列表for file in filelist://刪除gif和png圖片if file.endswith('.gif') or file.endswith('.GIF') or file.endswith('.png') or file.endswith('.PNG'):os.remove(file)continue# 對圖片以數字編號重命名os.rename(file, path + str(name) + '.jpg')name += 1執行上面的方法後我們就把合適的圖片篩選出來了。
3.2、獲取顏色的主色調列表
獲取主色調列表前我們需要先獲取主色調,這裡直接使用bgr值的平均值作為主色調:
def getDominant(im):"""獲取主色調"""b = int(round(np.mean(im[:, :, 0])))g = int(round(np.mean(im[:, :, 1])))r = int(round(np.mean(im[:, :, 2])))return (b, g, r)通常RGB模式的圖片我們接觸的比較多,但是在OpenCV中圖片是以BGR模式讀取,每個字母的含義是一樣的,只是順序不同,這裡需要注意一下。接下來我們獲取主色調列表:
def getColors(path):"""獲取圖片列表的色調表"""colors =# 獲取圖片列表filelist = [path + i for i in os.listdir(path)]# 遍歷列表for file in filelist:# 讀取圖片im = cv2.imdecode(np.fromfile(file, dtype=np.uint8), -1)try:# 獲取圖片主色調dominant = getDominant(im)except:continue# 將主色調添加到色調列表中colors.append(dominant)return colors有了色調列表,我們對比顏色的操作就可以直接同色調列表進行了。
3.3、尋找主色調最接近的圖片
我是通過比較兩張圖片主色調的BGR值,然後將差的絕對值相加的方式獲得色調的差異:
def fitColor(color1, color2):"""返回兩個顏色之間的差異大小"""# 求出b通道之間的差異b = color1[0] - color2[0]# 求出g通道之間的差異g = color1[1] - color2[1]# 求出r通道之間的差異r = color1[2] - color2[2]# 返回絕對值的和return abs(b) + abs(g) + abs(r)
3.4、遍歷,尋找並粘貼
這裡就是我們的方法主體了,內容比較多,我們先看看代碼:
def generate(im_path, imgs_path, box_size, multiple=1):"""生成圖片"""# 讀取圖片列表img_list = [imgs_path + i for i in os.listdir(imgs_path)]# 讀取圖片im = cv2.imread(im_path)im = cv2.resize(im, (im.shape[1]*multiple, im.shape[0]*multiple))# 獲取圖片寬高width, height = im.shape[1], im.shape[0]# 遍歷圖片像素for i in range(height // box_size+1):for j in range(width // box_size+1):# 圖塊起點坐標start_x, start_y = j * box_size, i * box_size# 初始化圖片塊的寬高box_w, box_h = box_size, box_size# 截取當前遍歷到的圖塊box_im = im[start_y:, start_x:]if i == height // box_size:box_h = box_im.shape[0]if j == width // box_size:box_w = box_im.shape[1]if box_h == 0 or box_w == 0:continue# 獲取主色調dominant = getDominant(im[start_y:start_y+box_h, start_x:start_x+box_w])img_loc = 0# 差異,同主色調最大差異為255*3dif = 255 * 3# 遍歷色調表,查找差異最小的圖片for index in range(colors.__len__):if fitColor(dominant, colors[index]) < dif:dif = fitColor(dominant, colors[index])# 色調列表同圖片列表的位置是一致的,所以我們獲取色調下標即可img_loc = index# 讀取差異最小的圖片,img_list[img_loc]為差異最小的圖片box_im = cv2.imdecode(np.fromfile(img_list[img_loc], dtype=np.uint8), -1)# 轉換成合適的大小box_im = cv2.resize(box_im, (box_w, box_h))# 鋪墊色塊im[start_y:start_y+box_h, start_x:start_x+box_w] = box_imj += box_wi += box_h# 返回結果圖return im首先我們看看傳入的參數都是什麼含義:
im_path : 底圖的路徑imgs_path : 圖片列表的根目錄box_size : 像素塊的大小multiple=1 : 圖片的縮放大小,默認為1前面兩個參數非常好理解。對於box_size參數的解釋就是效果圖四種,每張照片的尺寸,因為我全部以正方形處理,所以只有一個大小。而multiple參數則是縮放大小,當我們底圖為50*50沒有設置縮放時,結果圖也是50*50,當我們將縮放設置為2,結果圖則為100*100。因為圖片太小的話看不到像素塊中的圖片,所以利用縮放讓效果更好,但是縮放值設置過大的話圖片內存會大許多。其它部分的解釋都在代碼中了。最後再給大家看一張效果圖:
效果圖片
因為事先效果不是非常樂觀,所以給大家看一張朦朧的效果圖。
真沒想到,Python還能實現5毛特效作詞家下崗系列:教你用 AI 做一個寫歌詞的軟體AI修復100年前晚清影像喜提熱搜,這兩大算法立功了阿里雲自研數據倉庫 AnalyticDB 再捧 TPC 全球冠軍調查了 17,000 多位程式設計師,當前的雲原生開發現狀究竟如何?CSW:驚天巨騙 or 比特幣「圖騰」中本聰?從 0 到 70%:Chrome 上位揭秘!