home *** CD-ROM | disk | FTP | other *** search
/ Planet Source Code Jumbo …e CD Visual Basic 1 to 7 / 6_2008-2009.ISO / data / zips / A_Real_Inp2140301122009.psc / Inpainting.bas < prev   
BASIC Source File  |  2009-01-11  |  15KB  |  422 lines

  1. Attribute VB_Name = "Inpainting"
  2. Option Explicit
  3. 'Real Image InPainting
  4. 'VB Version 2009 by Scythe
  5. 'Thanks goes to Qiushuang Zhang
  6. 'Who made the Original as C++ Source
  7. Private Type Bitmap
  8.     bmType As Long
  9.     bmWidth As Long
  10.     bmHeight As Long
  11.     bmWidthBytes As Long
  12.     bmPlanes As Integer
  13.     bmBitsPixel As Integer
  14.     bmBits As Long
  15. End Type
  16.  
  17. Private Declare Function GetObject Lib "gdi32" Alias "GetObjectA" (ByVal hObject As Long, ByVal nCount As Long, lpObject As Any) As Long
  18. Private Declare Function GetBitmapBits Lib "gdi32" (ByVal hBitmap As Long, ByVal dwCount As Long, lpBits As Any) As Long
  19. Private Declare Function SetBitmapBits Lib "gdi32" (ByVal hBitmap As Long, ByVal dwCount As Long, lpBits As Any) As Long
  20. Private Type RGBQUAD
  21.     rgbBlue As Byte
  22.     rgbgreen As Byte
  23.     rgbRed As Byte
  24.     rgbReserved As Byte
  25. End Type
  26.  
  27. Private PicInfo As Bitmap
  28. Private PicAr1() As RGBQUAD
  29. Public StopIt As Boolean 'Stop the inpainting
  30.  
  31. Private Type gradient
  32.     grad_x As Double
  33.     grad_y As Double
  34. End Type 'the structure that record the gradient
  35.  
  36. Private Type norm
  37.     norm_x As Double
  38.     norm_y As Double
  39. End Type ' the structure that record the norm
  40.  
  41.     Const Source = 0
  42. Private Winsize As Long
  43. Private m_width As Long ' image width
  44. Private m_height As Long ' image height
  45. Private m_color() As RGBQUAD
  46. Private m_r() As Double
  47. Private m_g() As Double
  48. Private m_b() As Double
  49. Private m_top As Integer ' the rectangle of inpaint area
  50. Private m_bottom As Integer
  51. Private m_left As Integer
  52. Private m_right As Integer
  53. Private m_mark() As Integer ' mark it as source(0) or to-be-inpainted area(-1) or bondary(-2).
  54. Private m_confid() As Double ' record the confidence for every pixel
  55. Private m_pri() As Double ' record the priority for pixels. only boudary pixels will be used
  56. Private m_gray() As Double ' the gray image
  57. Private m_source() As Boolean ' whether this pixel can be used as an example texture center
  58. Private PatchL As Long
  59. Private PatchR As Long
  60. Private PatchT As Long
  61. Private PatchB As Long
  62.  
  63.  
  64. 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
  65.  
  66. Dim BufSize As Long
  67. Dim X As Long
  68. Dim Y As Long
  69. Dim j As Long
  70. Dim i As Long
  71. Dim Count As Long
  72. 'Get the Picture
  73.     Pic2Array InPicture, PicAr1
  74. 'Fill our Used Variables
  75.     m_width = UBound(PicAr1, 1) + 1
  76.     m_height = UBound(PicAr1, 2) + 1
  77.     Winsize = BlockSize
  78.     BufSize = m_width
  79.     BufSize = BufSize * m_height - 1
  80.     ReDim m_mark(BufSize)
  81.     ReDim m_confid(BufSize)
  82.     ReDim m_pri(BufSize)
  83.     ReDim m_gray(BufSize)
  84.     ReDim m_source(BufSize)
  85.     ReDim m_color(BufSize)
  86.     ReDim m_r(BufSize)
  87.     ReDim m_g(BufSize)
  88.     ReDim m_b(BufSize)
  89.     ReDim m_confid(BufSize)
  90. Dim max_pri As Double
  91. Dim pri_x As Long
  92. Dim pri_y As Long
  93. Dim patch_x As Long
  94. Dim patch_y As Long
  95. Dim Jidx As Long
  96.  
  97.     m_top = m_height ' initialize the rectangle area
  98.  
  99.     m_bottom = 0
  100.     m_left = m_width
  101.     m_right = 0
  102. 'Now fill some of the Variables
  103.     For Y = 0 To m_height - 1
  104.         j = Y * m_width
  105.         For X = 0 To m_width - 1
  106.             i = j + X
  107.             m_color(i) = PicAr1(X, Y)
  108.             m_r(i) = PicAr1(X, Y).rgbRed
  109.             m_g(i) = PicAr1(X, Y).rgbgreen
  110.             m_b(i) = PicAr1(X, Y).rgbBlue
  111.         Next X
  112.     Next Y
  113.     Convert2Gray  ' convert it to gray image
  114.     DrawBoundary MaskRed, MaskGreen, MaskBlue ' first time draw boundary
  115. 'Set Boundary for PatchTexture
  116.     PatchL = IIf(m_left - BorderSize < 0, 0, m_left - BorderSize)
  117.     PatchR = IIf(m_right + BorderSize > m_width - 1, m_width - 1, m_right + BorderSize)
  118.     PatchT = IIf(m_top - BorderSize < 0, 0, m_top - BorderSize)
  119.     PatchB = IIf(m_bottom + BorderSize > m_height - 1, m_height - 1, m_bottom + BorderSize)
  120.     draw_source ' find the patches that can be used as sample texture
  121.     For j = m_top To m_bottom
  122.         Y = j * m_width
  123.         For i = m_left To m_right  'if it is boundary, calculate the priority
  124.             If m_mark(Y + i) = -2 Then
  125.                 m_pri(Y + i) = priority(i, j)
  126.             End If
  127.         Next i
  128.     Next j
  129. 'Now the real function
  130.     Do While TargetExist()
  131.         max_pri = 0
  132.         Count = Count + 1
  133.         For j = m_top To m_bottom
  134.             Jidx = j * m_width
  135.             For i = m_left To m_right
  136.                 If m_mark(Jidx + i) = -2 And m_pri(Jidx + i) > max_pri Then ' find the boundary pixel with highest priority
  137.                     pri_x = i
  138.                     pri_y = j
  139.                     max_pri = m_pri(Jidx + i)
  140.                 End If
  141.             Next i
  142.         Next j
  143.         DoEvents
  144.         If StopIt Then Exit Function
  145.         PatchTexture pri_x, pri_y, patch_x, patch_y ' find the most similar source patch
  146.         DoEvents
  147.         If StopIt Then Exit Function
  148.         update pri_x, pri_y, patch_x, patch_y, ComputeConfidence(pri_x, pri_y) ' inpaint this area and update confidence
  149.         DoEvents
  150.         If StopIt Then Exit Function
  151.         UpdateBoundary pri_x, pri_y, MaskRed, MaskGreen, MaskBlue ' update boundary near the changed area
  152.         DoEvents
  153.         If StopIt Then Exit Function
  154.         UpdatePri pri_x, pri_y  ' update priority near the changed area
  155.         DoEvents
  156.         If StopIt Then Exit Function
  157.         If Preview Then
  158.             Array2Pic ResultPicture, PicAr1
  159.             ResultPicture.Refresh
  160.             DoEvents
  161.         End If
  162.     Loop
  163.     DoInPaint = Count
  164.     Array2Pic ResultPicture, PicAr1
  165.     ResultPicture.Picture = ResultPicture.Image
  166.     ResultPicture.Refresh
  167.  
  168. End Function
  169. Private Sub DrawBoundary(MaskRed As Byte, MaskGreen As Byte, MaskBlue As Byte)
  170.  
  171. Dim X As Long
  172. Dim Y As Long
  173. Dim j As Long
  174. Dim i As Long
  175. Dim Found As Boolean
  176.     On Error Resume Next
  177.  
  178.     For Y = 0 To m_height - 1
  179.         For X = 0 To m_width - 1
  180.             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
  181.                 m_mark(Y * m_width + X) = -1
  182.                 m_confid(Y * m_width + X) = 0
  183.                 Else
  184.                 m_mark(Y * m_width + X) = Source
  185.                 m_confid(Y * m_width + X) = 1
  186.             End If
  187.         Next X
  188.     Next Y
  189.     For j = 0 To m_height - 1
  190.         For i = 0 To m_width - 1
  191.             If m_mark(j * m_width + i) = -1 Then
  192.                 If i < m_left Then ' resize the rectangle to the range of target area
  193.                     m_left = i
  194.                 End If
  195.                 If i > m_right Then
  196.                     m_right = i
  197.                 End If
  198.                 If j > m_bottom Then
  199.                     m_bottom = j
  200.                 End If
  201.                 If j < m_top Then
  202.                     m_top = j
  203.                 End If
  204. 'if one of the four neighbours is source pixel, then this should be a boundary
  205.                 If j = m_height - 1 Or j = 0 Or i = 0 Or i = m_width - 1 Then Found = True
  206.                 If m_mark(j * m_width + i + 1) = Source Then Found = True
  207.                 If m_mark(j * m_width + i - 1) = Source Then Found = True
  208.                 If m_mark((j + 1) * m_width + i) = Source Then Found = True
  209.                 If m_mark((j - 1) * m_width + i) = Source Then Found = True
  210.                 If Found Then
  211.                     Found = False
  212.                     m_mark(j * m_width + i) = -2
  213.                 End If
  214.             End If
  215.         Next i
  216.     Next j
  217.  
  218. End Sub
  219. Private Function ComputeConfidence(ByVal i As Long, ByVal j As Long) As Double
  220.  
  221. Dim confidence As Double
  222. Dim X As Long
  223. Dim Y As Long
  224.  
  225.     For Y = (IIf(((j - Winsize) > (0)), (j - Winsize), (0))) To (IIf(((j + Winsize) < (m_height - 1)), (j + Winsize), (m_height - 1)))
  226.         For X = (IIf(((i - Winsize) > (0)), (i - Winsize), (0))) To (IIf(((i + Winsize) < (m_width - 1)), (i + Winsize), (m_width - 1)))
  227.             confidence = confidence + m_confid(Y * m_width + X)
  228.         Next X
  229.     Next Y
  230.     confidence = confidence / ((Winsize * 2 + 1) * (Winsize * 2 + 1))
  231.     ComputeConfidence = confidence
  232.  
  233. End Function
  234. Private Function priority(ByVal i As Long, ByVal j As Long) As Double
  235.  
  236. Dim confidence As Double
  237. Dim data As Double
  238.     confidence = ComputeConfidence(i, j) ' confidence term
  239.  
  240.     data = ComputeData(i, j) ' data term
  241.     priority = confidence * data
  242.  
  243. End Function
  244. Private Function ComputeData(ByVal i As Long, ByVal j As Long) As Double
  245.  
  246. Dim grad As gradient
  247. Dim temp As gradient
  248. Dim grad_T As gradient
  249.     grad.grad_x = 0
  250.  
  251.     grad.grad_y = 0
  252. Dim result As Double
  253. Dim magnitude As Double
  254. Dim max As Double
  255. Dim X As Long
  256. Dim Y As Long
  257. Dim nn As norm
  258. Dim Found As Boolean
  259.     On Error Resume Next
  260.  
  261.     For Y = (IIf(((j - Winsize) > (0)), (j - Winsize), (0))) To (IIf(((j + Winsize) < (m_height - 1)), (j + Winsize), (m_height - 1)))
  262.         For X = (IIf(((i - Winsize) > (0)), (i - Winsize), (0))) To (IIf(((i + Winsize) < (m_width - 1)), (i + Winsize), (m_width - 1)))
  263. ' find the greatest gradient in this patch, this will be the gradient of this pixel
  264.             If m_mark(Y * m_width + X) >= 0 Then ' source pixel
  265. 'since I use four neighbors to calculate the gradient, make sure this four neighbors do not touch target region(big jump in gradient)
  266.                 Found = False
  267.                 If m_mark(Y * m_width + X + 1) < 0 Then Found = True
  268.                 If m_mark(Y * m_width + X - 1) < 0 Then Found = True
  269.                 If m_mark((Y + 1) * m_width + X) < 0 Then Found = True
  270.                 If m_mark((Y - 1) * m_width + X) < 0 Then Found = True
  271.                 If Found = False Then
  272.                     temp = GetGradient(X, Y)
  273.                     magnitude = temp.grad_x * temp.grad_x + temp.grad_y * temp.grad_y
  274.                     If magnitude > max Then
  275.                         grad.grad_x = temp.grad_x
  276.                         grad.grad_y = temp.grad_y
  277.                         max = magnitude
  278.                     End If
  279.                 End If
  280.             End If
  281.         Next X
  282.     Next Y
  283.     grad_T.grad_x = grad.grad_y ' perpendicular to the gradient: (x,y)->(y, -x)
  284.     grad_T.grad_y = -grad.grad_x
  285.     nn = GetNorm(i, j)
  286.     result = nn.norm_x * grad_T.grad_x + nn.norm_y * grad_T.grad_y ' dot product
  287.     result = result / 255 '"alpha" in the paper: normalization factor
  288.     result = Abs(result)
  289.     ComputeData = result
  290.  
  291. End Function
  292. 'Get a gray Picture
  293. Private Sub Convert2Gray()
  294.  
  295. Dim r As Double
  296. Dim g As Double
  297. Dim b As Double
  298. Dim X As Long
  299. Dim Y As Long
  300.  
  301.     For Y = 0 To m_height - 1
  302.         For X = 0 To m_width - 1
  303.             r = PicAr1(X, Y).rgbRed
  304.             g = PicAr1(X, Y).rgbgreen
  305.             b = PicAr1(X, Y).rgbBlue
  306.             m_gray(Y * m_width + X) = CDbl((r * 3735 + g * 19267 + b * 9765) / 32767)
  307.         Next X
  308.     Next Y
  309.  
  310. End Sub
  311. 'Calculate the Gradient
  312. Private Function GetGradient(ByVal i As Long, ByVal j As Long) As gradient
  313.  
  314. Dim result As gradient
  315.     result.grad_x = (m_gray(j * m_width + i + 1) - m_gray(j * m_width + i - 1)) / 2#
  316.  
  317.     result.grad_y = (m_gray((j + 1) * m_width + i) - m_gray((j - 1) * m_width + i)) / 2#
  318.     If i = 0 Then
  319.         result.grad_x = m_gray(j * m_width + i + 1) - m_gray(j * m_width + i)
  320.     End If
  321.     If i = m_width - 1 Then
  322.         result.grad_x = m_gray(j * m_width + i) - m_gray(j * m_width + i - 1)
  323.     End If
  324.     If j = 0 Then
  325.         result.grad_y = m_gray((j + 1) * m_width + i) - m_gray(j * m_width + i)
  326.     End If
  327.     If j = m_height - 1 Then
  328.         result.grad_y = m_gray(j * m_width + i) - m_gray((j - 1) * m_width + i)
  329.     End If
  330.     GetGradient = result
  331.  
  332. End Function
  333. 'Find the Normals
  334. Private Function GetNorm(ByVal i As Long, ByVal j As Long) As norm
  335.  
  336. Dim result As norm
  337. Dim num As Long
  338. Dim neighbor_x(8) As Long
  339. Dim neighbor_y(8) As Long
  340. Dim record(8) As Long
  341. Dim Count As Long
  342. Dim X As Long
  343. Dim Y As Long
  344. Dim n_x As Long
  345. Dim n_y As Long
  346. Dim temp As Long
  347. Dim square As Double
  348.  
  349.     For Y = (IIf(((j - 1) > (0)), (j - 1), (0))) To (IIf(((j + 1) < (m_height - 1)), (j + 1), (m_height - 1)))
  350.         For X = (IIf(((i - 1) > (0)), (i - 1), (0))) To (IIf(((i + 1) < (m_width - 1)), (i + 1), (m_width - 1)))
  351.             Count = Count + 1
  352.             If X <> i Or Y <> j Then
  353.                 If m_mark(Y * m_width + X) = -2 Then
  354.                     num = num + 1
  355.                     neighbor_x(num) = X
  356.                     neighbor_y(num) = Y
  357.                     record(num) = Count
  358.                 End If
  359.             End If
  360.         Next X
  361.     Next Y
  362.     If num = 0 Or num = 1 Then ' if it doesn't have two neighbors, give it a random number to proceed
  363.         result.norm_x = 0.6
  364.         result.norm_y = 0.8
  365.         GetNorm = result
  366.         Exit Function
  367.     End If
  368. ' draw a line between the two neighbors of the boundary pixel, then the norm is the perpendicular to the line
  369.     n_x = neighbor_x(2) - neighbor_x(1)
  370.     n_y = neighbor_y(2) - neighbor_y(1)
  371.     temp = n_x
  372.     n_x = n_y
  373.     n_y = temp
  374.     square = CDbl(n_x * n_x + n_y * n_y) ^ 0.5
  375.     If n_x = 0 Then
  376.         result.norm_x = 0
  377.         Else
  378.         result.norm_x = n_x / square
  379.     End If
  380.     If n_y = 0 Then
  381.         result.norm_y = 0
  382.         Else
  383.         result.norm_y = n_y / square
  384.     End If
  385.     GetNorm = result
  386.  
  387. End Function
  388. Private Function draw_source() As Boolean
  389.  
  390. ' draw a window around the pixel, if all of the points within the window are source pixels, then this patch can be used as a source patch
  391. Dim X As Long
  392. Dim Y As Long
  393. Dim i As Long
  394. Dim j As Long
  395. Dim flag As Boolean
  396.  
  397.     For j = 0 To m_height - 1
  398.         For i = 0 To m_width - 1
  399.             flag = True
  400.             If i < Winsize Or j < Winsize Or i >= m_width - Winsize Or j >= m_height - Winsize Then 'cannot form a complete window
  401.                 m_source(j * m_width + i) = False
  402.                 Else
  403.                 For Y = j - Winsize To j + Winsize
  404.                     For X = i - Winsize To i + Winsize
  405.                         If m_mark(Y * m_width + X) <> Source Then
  406.                             m_source(j * m_width + i) = False
  407.                             flag = False
  408.                             Exit For
  409.                         End If
  410.                     Next X
  411.                     If flag = False Then
  412.                         Exit For
  413.                     End If
  414.                 Next Y
  415.                 If flag <> False Then
  416.                     m_source(j * m_width + i) = True
  417.                          If i < m_left Then ' resize the rectangle to th3f         Next X
  418.                                   ' resize the rectangle to th3f         Next X
  419.           ' resize the rectangle to th3f  e lse
  420.                             Exit For
  421.                         End If
  422.