Private Declare Function GetObject Lib "gdi32" Alias "GetObjectA" (ByVal hObject As Long, ByVal nCount As Long, lpObject As Any) As Long
Private Declare Function GetBitmapBits Lib "gdi32" (ByVal hBitmap As Long, ByVal dwCount As Long, lpBits As Any) As Long
Private Declare Function SetBitmapBits Lib "gdi32" (ByVal hBitmap As Long, ByVal dwCount As Long, lpBits As Any) As Long
Private Type RGBQUAD
rgbBlue As Byte
rgbgreen As Byte
rgbRed As Byte
rgbReserved As Byte
End Type
Private PicInfo As Bitmap
Private PicAr1() As RGBQUAD
Public StopIt As Boolean 'Stop the inpainting
Private Type gradient
grad_x As Double
grad_y As Double
End Type 'the structure that record the gradient
Private Type norm
norm_x As Double
norm_y As Double
End Type ' the structure that record the norm
Const Source = 0
Private Winsize As Long
Private m_width As Long ' image width
Private m_height As Long ' image height
Private m_color() As RGBQUAD
Private m_r() As Double
Private m_g() As Double
Private m_b() As Double
Private m_top As Integer ' the rectangle of inpaint area
Private m_bottom As Integer
Private m_left As Integer
Private m_right As Integer
Private m_mark() As Integer ' mark it as source(0) or to-be-inpainted area(-1) or bondary(-2).
Private m_confid() As Double ' record the confidence for every pixel
Private m_pri() As Double ' record the priority for pixels. only boudary pixels will be used
Private m_gray() As Double ' the gray image
Private m_source() As Boolean ' whether this pixel can be used as an example texture center
Private PatchL As Long
Private PatchR As Long
Private PatchT As Long
Private PatchB As Long
Public Function DoInPaint(InPicture As PictureBox, ResultPicture As PictureBox, MaskRed As Byte, MaskGreen As Byte, MaskBlue As Byte, Optional Preview As Boolean = False, Optional BlockSize As Long = 4, Optional BorderSize As Long = 10000) As Long
Dim BufSize As Long
Dim X As Long
Dim Y As Long
Dim j As Long
Dim i As Long
Dim Count As Long
'Get the Picture
Pic2Array InPicture, PicAr1
'Fill our Used Variables
m_width = UBound(PicAr1, 1) + 1
m_height = UBound(PicAr1, 2) + 1
Winsize = BlockSize
BufSize = m_width
BufSize = BufSize * m_height - 1
ReDim m_mark(BufSize)
ReDim m_confid(BufSize)
ReDim m_pri(BufSize)
ReDim m_gray(BufSize)
ReDim m_source(BufSize)
ReDim m_color(BufSize)
ReDim m_r(BufSize)
ReDim m_g(BufSize)
ReDim m_b(BufSize)
ReDim m_confid(BufSize)
Dim max_pri As Double
Dim pri_x As Long
Dim pri_y As Long
Dim patch_x As Long
Dim patch_y As Long
Dim Jidx As Long
m_top = m_height ' initialize the rectangle area
m_bottom = 0
m_left = m_width
m_right = 0
'Now fill some of the Variables
For Y = 0 To m_height - 1
j = Y * m_width
For X = 0 To m_width - 1
i = j + X
m_color(i) = PicAr1(X, Y)
m_r(i) = PicAr1(X, Y).rgbRed
m_g(i) = PicAr1(X, Y).rgbgreen
m_b(i) = PicAr1(X, Y).rgbBlue
Next X
Next Y
Convert2Gray ' convert it to gray image
DrawBoundary MaskRed, MaskGreen, MaskBlue ' first time draw boundary
draw_source ' find the patches that can be used as sample texture
For j = m_top To m_bottom
Y = j * m_width
For i = m_left To m_right 'if it is boundary, calculate the priority
If m_mark(Y + i) = -2 Then
m_pri(Y + i) = priority(i, j)
End If
Next i
Next j
'Now the real function
Do While TargetExist()
max_pri = 0
Count = Count + 1
For j = m_top To m_bottom
Jidx = j * m_width
For i = m_left To m_right
If m_mark(Jidx + i) = -2 And m_pri(Jidx + i) > max_pri Then ' find the boundary pixel with highest priority
pri_x = i
pri_y = j
max_pri = m_pri(Jidx + i)
End If
Next i
Next j
DoEvents
If StopIt Then Exit Function
PatchTexture pri_x, pri_y, patch_x, patch_y ' find the most similar source patch
DoEvents
If StopIt Then Exit Function
update pri_x, pri_y, patch_x, patch_y, ComputeConfidence(pri_x, pri_y) ' inpaint this area and update confidence
DoEvents
If StopIt Then Exit Function
UpdateBoundary pri_x, pri_y, MaskRed, MaskGreen, MaskBlue ' update boundary near the changed area
DoEvents
If StopIt Then Exit Function
UpdatePri pri_x, pri_y ' update priority near the changed area
DoEvents
If StopIt Then Exit Function
If Preview Then
Array2Pic ResultPicture, PicAr1
ResultPicture.Refresh
DoEvents
End If
Loop
DoInPaint = Count
Array2Pic ResultPicture, PicAr1
ResultPicture.Picture = ResultPicture.Image
ResultPicture.Refresh
End Function
Private Sub DrawBoundary(MaskRed As Byte, MaskGreen As Byte, MaskBlue As Byte)
Dim X As Long
Dim Y As Long
Dim j As Long
Dim i As Long
Dim Found As Boolean
On Error Resume Next
For Y = 0 To m_height - 1
For X = 0 To m_width - 1
If PicAr1(X, Y).rgbRed = MaskRed And PicAr1(X, Y).rgbgreen = MaskGreen And PicAr1(X, Y).rgbBlue = MaskBlue Then ' if the pixel is specified as boundary
m_mark(Y * m_width + X) = -1
m_confid(Y * m_width + X) = 0
Else
m_mark(Y * m_width + X) = Source
m_confid(Y * m_width + X) = 1
End If
Next X
Next Y
For j = 0 To m_height - 1
For i = 0 To m_width - 1
If m_mark(j * m_width + i) = -1 Then
If i < m_left Then ' resize the rectangle to the range of target area
m_left = i
End If
If i > m_right Then
m_right = i
End If
If j > m_bottom Then
m_bottom = j
End If
If j < m_top Then
m_top = j
End If
'if one of the four neighbours is source pixel, then this should be a boundary
If j = m_height - 1 Or j = 0 Or i = 0 Or i = m_width - 1 Then Found = True
If m_mark(j * m_width + i + 1) = Source Then Found = True
If m_mark(j * m_width + i - 1) = Source Then Found = True
If m_mark((j + 1) * m_width + i) = Source Then Found = True
If m_mark((j - 1) * m_width + i) = Source Then Found = True
If Found Then
Found = False
m_mark(j * m_width + i) = -2
End If
End If
Next i
Next j
End Sub
Private Function ComputeConfidence(ByVal i As Long, ByVal j As Long) As Double
Dim confidence As Double
Dim X As Long
Dim Y As Long
For Y = (IIf(((j - Winsize) > (0)), (j - Winsize), (0))) To (IIf(((j + Winsize) < (m_height - 1)), (j + Winsize), (m_height - 1)))
For X = (IIf(((i - Winsize) > (0)), (i - Winsize), (0))) To (IIf(((i + Winsize) < (m_width - 1)), (i + Winsize), (m_width - 1)))