Python,OpenCV中的影像修復——cv2.inpaint
- 1. 效果圖
- 2. 原理
- 3. 原始碼
- 參考
image inpainting 影像修改
這篇博客將介紹如何通過OpenCV中影像修復的技術——cv2.inpaint() 去除舊照片中的小噪音、筆劃等,并提供一個可互動式的程式,利用OpenCV的快速行進和流體力學倆種修復演算法對自己的圖片進行修復,
大多數人家里都會有一些舊的老化照片,上面有一些黑點、筆劃等,如何復原呢?
在繪制工具中擦除:將簡單地用無用的白色結構替換黑色結構,效果并不理想,OpenCV中影像修復的技術——基本思想很簡單:用相鄰像素替換這些壞標記,使其看起來像鄰居,
-
cv2.INPAINT_TELEA(Fast Marching Method 快速行進演算法)
-
cv2.INPAINT_NS(Fluid Dynamics Method 流體力學演算法)
-
OpenCV未實作的:Content-Aware Fill 內容感知填充演算法,這是Adobe Photoshop中使用的一種高級修復技術,
cv2.inpaint() 優點:修復效果更加自然;
缺點:修復時需要提供原圖以及mask圖(與原圖一致只有被污染的像素區域有值);
1. 效果圖
官方原始圖 VS mask圖 VS 快速行進演算法修復效果 VS 流體力學修復效果 如下:

接下來用可互動的例子實作自己的圖片修復;
原始圖 VS Mask圖 VS 快速行進演算法修復效果圖如下:
原始圖隨意用滑鼠左鍵移動繪制點、線,右鍵移動繪制矩形來隨機增加一些被污染的區域;
并根據原始圖生成mask圖,mask圖是與原始圖具有相同大小,并且只有被污染的區域是白色像素的圖,可以看到修復效果還是挺好的~
原始圖 VS Mask圖 VS 流體力學演算法修復效果圖如下:
原始圖隨意用滑鼠左鍵移動繪制點、線,右鍵移動繪制矩形來隨機增加一些被污染的區域;
mask圖是與原始圖具有相同大小,并且只有被污染的區域是白色像素的圖,可以看到修復效果還是挺好的~

快速行進演算法與流體力學演算法修復的效果圖差別不太大;
2. 原理
-
cv2.INPAINT_TELEA (Fast Marching Method 快速行進演算法),對位于點附近、邊界法線附近和邊界輪廓上的像素賦予更多權重,一旦一個像素被修復,它將使用快速行進的方法移動到下一個最近的像素,
-
cv2.INPAINT_NS(Fluid Dynamics Method 流體力學演算法),使用了流體力學的一些方法,基本原則是啟發式的,首先沿著邊從已知區域移動到未知區域(因為邊是連續的),它在匹配修復區域邊界處的漸變向量的同時,繼續等高線(連接具有相同強度的點的線,就像等高線連接具有相同高程的點一樣),
-
OpenCV未實作的:Content-Aware Fill 內容感知填充演算法,這是Adobe Photoshop中使用的一種高級修復技術,
3. 原始碼
# 影像修復互動式案例——通過水流填充演算法來修復被破壞的影像區域;
# 使用倆種方法進行修復
# cv2.INPAINT_TELEA (Fast Marching Method 快速行進演算法),對位于點附近、邊界法線附近和邊界輪廓上的像素賦予更多權重,一旦一個像素被修復,它將使用快速行進的方法移動到下一個最近的像素,
# cv2.INPAINT_NS 流體力學演算法,使用了流體力學的一些方法,基本原則是啟發式的,首先沿著邊從已知區域移動到未知區域(因為邊是連續的),它在匹配修復區域邊界處的漸變向量的同時,繼續等高線(連接具有相同強度的點的線,就像等高線連接具有相同高程的點一樣),
# USAGE
# python inpaint.py D:/deepLearning/py-demo/20210808/images/ml.jpg
# 按下滑鼠左鍵,添加點、線,按下滑鼠右鍵,添加矩形框,以制作被污染的需要修復影像
# 按下空格鍵:執行修復功能
# 按下r鍵:重置待修復的mask
# 按下esc鍵,退出
import cv2
import numpy as np
class Sketcher:
def __init__(self, windowname, dests, colors_func):
self.prev_pt = None # 線起始點
self.drag_start = None # 矩形起點
self.drag_rect = None # 矩形(左上角,右下角)坐標
self.windowname = windowname
self.dests = dests
self.colors_func = colors_func
self.dirty = False
self.drawing = False
self.mode = False
self.show()
cv2.setMouseCallback(self.windowname, self.on_mouse)
def show(self):
cv2.imshow(self.windowname, self.dests[0])
def on_mouse(self, event, x, y, flags, param):
pt = (x, y)
if event == cv2.EVENT_LBUTTONDOWN:
self.prev_pt = pt
self.drawing = True
elif event == cv2.EVENT_RBUTTONDOWN:
# 第一次初始化時設定pt,往后保留上一個點作為矩形起點
if self.drag_start == None:
self.drag_start = pt
if self.prev_pt and flags & cv2.EVENT_FLAG_LBUTTON:
for dst, color in zip(self.dests, self.colors_func()):
cv2.line(dst, self.prev_pt, pt, color, 5)
self.dirty = True
self.prev_pt = pt
self.show()
if self.drag_start and flags & cv2.EVENT_FLAG_RBUTTON:
xo, yo = self.drag_start
x0, y0 = np.minimum([xo, yo], [x, y])
x1, y1 = np.maximum([xo, yo], [x, y])
self.drag_rect = None
if x1 - x0 > 0 and y1 - y0 > 0:
self.drag_rect = (x0, y0, x1, y1)
for dst, color in zip(self.dests, self.colors_func()):
cv2.rectangle(dst, (x0, y0), (x1, y1), color, -1)
self.dirty = True
self.drag_start = None
self.drag_rect = None
self.show()
else:
self.drag_start = pt
@property
def dragging(self):
return self.drag_rect is not None
def main():
import sys
try:
fn = sys.argv[1]
except:
fn = 'images/ml_.jpg'
img = cv2.imread(fn)
if img is None:
print('Failed to load image file:', fn)
sys.exit(1)
img_mark = img.copy()
mark = np.zeros(img.shape[:2], np.uint8)
sketch = Sketcher('img', [img_mark, mark], lambda: ((255, 255, 255), 255))
while True:
ch = cv2.waitKey()
if ch == 27:
break
if ch == ord(' '):
cv2.imshow('mask', mark)
fmmres = cv2.inpaint(img_mark, mark, 3, cv2.INPAINT_TELEA)
nsres = cv2.inpaint(img_mark, mark, 3, cv2.INPAINT_NS)
cv2.imshow('inpaint fmm res', fmmres)
cv2.imshow('inpaint ns res', nsres)
if ch == ord('r'):
img_mark[:] = img
mark[:] = 0
sketch.show()
print('Done')
if __name__ == '__main__':
main()
cv2.destroyAllWindows()
參考
- https://docs.opencv.org/3.0-beta/doc/py_tutorials/py_photo/py_inpainting/py_inpainting.html#inpainting
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/293271.html
標籤:其他
上一篇:2021-08-10
