Skip to main content
Code Review

Return to Question

replaced http://codereview.stackexchange.com/ with https://codereview.stackexchange.com/
Source Link

This is my firstish (heavily rewritten) go at the completed project that I've been working on with CodeReview assistance, so further advice is appreciated! See here here, here here and here here for the past history of the project.

This is my firstish (heavily rewritten) go at the completed project that I've been working on with CodeReview assistance, so further advice is appreciated! See here, here and here for the past history of the project.

This is my firstish (heavily rewritten) go at the completed project that I've been working on with CodeReview assistance, so further advice is appreciated! See here, here and here for the past history of the project.

Code works now
Source Link
Ken
  • 653
  • 4
  • 12

This is my firstfirstish (heavily rewritten) go at the completed project that I've been working on with CodeReview assistance, so further advice is appreciated! See here, here and here for the past history of the project.

I've been doing some testing and discovered (andI have now fixed) a few logical bugs. I'm testing using two images where I know one is located inside the otherseparate set of unit tests (and have verified this using another algorithmvisible here) but it appearswhich confirm that this code currently can not find matches, though it appears correctworks with my two sample image sets.

namespace MathAlgorithms
module ArrayFunctions = 
 // Generic because it makes testing easier, yay math
 let SearchSubset (tSmallArray:'a[][]) (tLargeArray:'a[][]) (pCoordinate:(int * int)) =
 let tSmallHeight = tSmallArray.Length
 let tSmallWidth = tSmallArray.[0].Length
 let tHeightIndex = fst pCoordinate
 let tWidthIndex = snd pCoordinate
 let mutable tSmallHeightIndex = 0
 let mutable tSmallWidthIndex = 0
 let mutable tMatch = true
 try 
 while ( tSmallHeightIndex < tSmallHeight - 1 ) && tMatch do
 while ( tSmallWidthIndex < tSmallWidth - 1 ) && tMatch do
 let tLargeCurrentValue = tLargeArray.[tHeightIndex + tSmallHeightIndex].[tWidthIndex + tSmallWidthIndex]
 let tSmallCurrentValue = tSmallArray.[tSmallHeightIndex].[tSmallWidthIndex]
 if tSmallCurrentValue = tLargeCurrentValue then
 tSmallWidthIndex <- tSmallWidthIndex + 1 
 else
 tMatch <- false
 tSmallWidthIndex <- 0
 tSmallHeightIndex <- tSmallHeightIndex + 1
 tMatch
 with
 | _ -> false
namespace FsharpImaging
open System
open System.Drawing
open System.Drawing.Imaging
open System.Runtime.InteropServices
open MathAlgorithms
module ImageSearchImageFunctions = 
 let LoadBitmapIntoArray (pBitmap:Bitmap) =
 let tBitmapData = pBitmap.LockBits( Rectangle(Point.Empty, pBitmap.Size), 
 ImageLockMode.ReadOnly, 
 PixelFormat.Format24bppRgb ) 
 // Bitmap.Stride can be negative to indicate different orientation of the bitmap
 let tImageArrayLength = Math.Abs(tBitmapData.Stride) * pBitmap.Height
 let tImageDataArray = Array.zeroCreate<byte> tImageArrayLength
 
 // Marshal.Copy(tImageDataArray, 0, tBitmapData.Scan0, tImageArrayLength)
 Marshal.Copy(tBitmapData.Scan0, tImageDataArray, 0, tImageArrayLength)
 pBitmap.UnlockBits(tBitmapData)
 ( pBitmap.Width, pBitmap.Height, tBitmapData.Stride ), tImageDataArray
 // Notes:
 // Image pixel data is stored BGR ( blue green red )
 // Image data is padded to be divisible by 4 (int32 width)
 
 let Transform2D ( (pArrayWidthpDimension:intint*int*int), (pArray:byte[]) ) = 
 let tHeight = pArray.Length / ( pArrayWidth * 3 ) //tWidth, 3tHeight, bytestStride per= RGBpDimension
 [|
 for tHeightIndex in 0 .. ( tHeight - 1 ) do
 let tStart = tHeightIndex * ( pArrayWidth * 3 - 1 )tStride
 let tFinish = ( tStart + pArrayWidthtWidth * 3 ) - 1
 yield [| 
 for tWidthIndex in tStart .. 3 .. tFinish do
 yield ( pArray.[tWidthIndex]
 , pArray.[tWidthIndex + 1] 
 , pArray.[tWidthIndex + 2] )
 |]
 |]
 let SearchSubset (tSmallArray:(byte * byte * byte)[][]) (tLargeArray:(byte * byte * byte)[][]) (pCoordinate:(int * int)) =
 let tSmallHeight = tSmallArray.Length
 let tSmallWidth = tSmallArray.[0].Length

 let tHeightIndex = fst pCoordinate
 let tWidthIndex = snd pCoordinate
 let mutable tSmallHeightIndex = 0
 let mutable tSmallWidthIndex = 0
 let mutable tMatch = true
 try 
 while ( tSmallHeightIndex < tSmallHeight - 1 ) && tMatch do
 while ( tSmallWidthIndex < tSmallWidth - 1 ) && tMatch do
 let tLargeCurrentValue = tLargeArray.[tHeightIndex + tSmallHeightIndex].[tWidthIndex + tSmallWidthIndex]
 let tSmallCurrentValue = tSmallArray.[tSmallHeightIndex].[tSmallWidthIndex]

 ifmodule tSmallCurrentValueImageSearch = tLargeCurrentValue then
 tSmallWidthIndex <- tSmallWidthIndex + 1 
 else
  tMatch <- false
 tSmallHeightIndex <- tSmallHeightIndex + 1
 tMatch
 with
 | _ ->open falseImageFunctions
 let SearchBitmap (pSmallBitmap:Bitmap) (pLargeBitmap:Bitmap) = 
 
 let tSmallArray = Transform2D <| LoadBitmapIntoArray pSmallBitmap 
 let tLargeArray = Transform2D <| LoadBitmapIntoArray pLargeBitmap
 
 let tSearchWidth = pLargeBitmap.Width - pSmallBitmap.Width
 let tSearchHeight = pLargeBitmap.Height - pSmallBitmap.Height
 let mutable tHeightIndex = 0
 let mutable tWidthIndex = 0
 let mutable tMatch = false
 let mutable tContinue = true
 while ( tHeightIndex < tSearchHeight - 1 ) && tContinue do
 while ( tWidthIndex < tSearchWidth - 1 ) && tContinue do
 let tCurrentValue = tLargeArray.[tHeightIndex].[tWidthIndex]
 let tFirstSmallPixel = tSmallArray.[0].[0]
 if tCurrentValue = tFirstSmallPixel then
 tMatch <- ArrayFunctions.SearchSubset tSmallArray tLargeArray ( tHeightIndex, tWidthIndex )
 if tMatch then tContinue <- false
 if tMatch = false && tContinue = true then
 tWidthIndex <- tWidthIndex + 1
 if tMatch = false && tContinue = true then
 tWidthIndex <- 0 // Reset to search next row
 tHeightIndex <- tHeightIndex + 1
 tMatch, tWidthIndex, tHeightIndex
namespace MainProgram
open System.Drawing
open System.Drawing.Imaging
open System.Diagnostics
open FsharpImaging
module Main = 
 [<EntryPoint>]
 let main (args:string[]) = 
 
 use tSmallBitmap = new Bitmap("testimage2"searchimage.bmp")
 use tLargeBitmap = new Bitmap("testimage1"containingimage.bmp")
 let tSuccess, xCoord, yCoord = SearchBitmap tSmallBitmap tLargeBitmap
 // General plan for looping
 // - Split single array for small image into 2d array of arrays
 // - Split single array for large image into 2d array of arrays
 // - Iterate through each array in large array looking for first value from small array
 // - If first value islet foundtSuccess, then check for complete row
 // - If row is complete then check for second row (and so on)
 // - Stop searching horizontally when remaining pixels are smaller than search image width
  // - Stop searching vertically when remaining pixels are smallerxCoord, thanyCoord search= imageImageSearch.SearchBitmap heighttSmallBitmap tLargeBitmap
 // Must return from function
 0

This is my first go at the completed project that I've been working on with CodeReview assistance, so further advice is appreciated! See here, here and here for the past history of the project.

I've been doing some testing and discovered (and have now fixed) a few logical bugs. I'm testing using two images where I know one is located inside the other (and have verified this using another algorithm) but it appears this code currently can not find matches, though it appears correct.

open System
open System.Drawing
open System.Drawing.Imaging
open System.Runtime.InteropServices
module ImageSearch = 
 let LoadBitmapIntoArray (pBitmap:Bitmap) =
 let tBitmapData = pBitmap.LockBits( Rectangle(Point.Empty, pBitmap.Size), 
 ImageLockMode.ReadOnly, 
 PixelFormat.Format24bppRgb ) 
 // Bitmap.Stride can be negative to indicate different orientation of the bitmap
 let tImageArrayLength = Math.Abs(tBitmapData.Stride) * pBitmap.Height
 let tImageDataArray = Array.zeroCreate<byte> tImageArrayLength
 
 // Marshal.Copy(tImageDataArray, 0, tBitmapData.Scan0, tImageArrayLength)
 Marshal.Copy(tBitmapData.Scan0, tImageDataArray, 0, tImageArrayLength)
 pBitmap.UnlockBits(tBitmapData)
 pBitmap.Width, tImageDataArray
 let Transform2D ( (pArrayWidth:int), (pArray:byte[]) ) = 
 let tHeight = pArray.Length / ( pArrayWidth * 3 ) // 3 bytes per RGB
 [|
 for tHeightIndex in 0 .. tHeight - 1 do
 let tStart = tHeightIndex * ( pArrayWidth * 3 - 1 )
 let tFinish = tStart + pArrayWidth * 3 - 1
 yield [| 
 for tWidthIndex in tStart .. 3 .. tFinish do
 yield ( pArray.[tWidthIndex]
 , pArray.[tWidthIndex + 1] 
 , pArray.[tWidthIndex + 2] )
 |]
 |]
 let SearchSubset (tSmallArray:(byte * byte * byte)[][]) (tLargeArray:(byte * byte * byte)[][]) (pCoordinate:(int * int)) =
 let tSmallHeight = tSmallArray.Length
 let tSmallWidth = tSmallArray.[0].Length

 let tHeightIndex = fst pCoordinate
 let tWidthIndex = snd pCoordinate
 let mutable tSmallHeightIndex = 0
 let mutable tSmallWidthIndex = 0
 let mutable tMatch = true
 try 
 while ( tSmallHeightIndex < tSmallHeight - 1 ) && tMatch do
 while ( tSmallWidthIndex < tSmallWidth - 1 ) && tMatch do
 let tLargeCurrentValue = tLargeArray.[tHeightIndex + tSmallHeightIndex].[tWidthIndex + tSmallWidthIndex]
 let tSmallCurrentValue = tSmallArray.[tSmallHeightIndex].[tSmallWidthIndex]

 if tSmallCurrentValue = tLargeCurrentValue then
 tSmallWidthIndex <- tSmallWidthIndex + 1 
 else
  tMatch <- false
 tSmallHeightIndex <- tSmallHeightIndex + 1
 tMatch
 with
 | _ -> false
 let SearchBitmap (pSmallBitmap:Bitmap) (pLargeBitmap:Bitmap) = 
 
 let tSmallArray = Transform2D <| LoadBitmapIntoArray pSmallBitmap 
 let tLargeArray = Transform2D <| LoadBitmapIntoArray pLargeBitmap
 
 let tSearchWidth = pLargeBitmap.Width - pSmallBitmap.Width
 let tSearchHeight = pLargeBitmap.Height - pSmallBitmap.Height
 let mutable tHeightIndex = 0
 let mutable tWidthIndex = 0
 let mutable tMatch = false
 let mutable tContinue = true
 while ( tHeightIndex < tSearchHeight - 1 ) && tContinue do
 while ( tWidthIndex < tSearchWidth - 1 ) && tContinue do
 let tCurrentValue = tLargeArray.[tHeightIndex].[tWidthIndex]
 let tFirstSmallPixel = tSmallArray.[0].[0]
 if tCurrentValue = tFirstSmallPixel then
 tMatch <- SearchSubset tSmallArray tLargeArray ( tHeightIndex, tWidthIndex )
 if tMatch then tContinue <- false
 if tMatch = false && tContinue = true then
 tWidthIndex <- tWidthIndex + 1
 if tMatch = false && tContinue = true then
 tHeightIndex <- tHeightIndex + 1
 tMatch, tWidthIndex, tHeightIndex
 [<EntryPoint>]
 let main (args:string[]) = 
 
 use tSmallBitmap = new Bitmap("testimage2.bmp")
 use tLargeBitmap = new Bitmap("testimage1.bmp")
 let tSuccess, xCoord, yCoord = SearchBitmap tSmallBitmap tLargeBitmap
 // General plan for looping
 // - Split single array for small image into 2d array of arrays
 // - Split single array for large image into 2d array of arrays
 // - Iterate through each array in large array looking for first value from small array
 // - If first value is found, then check for complete row
 // - If row is complete then check for second row (and so on)
 // - Stop searching horizontally when remaining pixels are smaller than search image width
  // - Stop searching vertically when remaining pixels are smaller than search image height 
 // Must return from function
 0

This is my firstish (heavily rewritten) go at the completed project that I've been working on with CodeReview assistance, so further advice is appreciated! See here, here and here for the past history of the project.

I have a separate set of unit tests (visible here) which confirm that this code works with my two sample image sets.

namespace MathAlgorithms
module ArrayFunctions = 
 // Generic because it makes testing easier, yay math
 let SearchSubset (tSmallArray:'a[][]) (tLargeArray:'a[][]) (pCoordinate:(int * int)) =
 let tSmallHeight = tSmallArray.Length
 let tSmallWidth = tSmallArray.[0].Length
 let tHeightIndex = fst pCoordinate
 let tWidthIndex = snd pCoordinate
 let mutable tSmallHeightIndex = 0
 let mutable tSmallWidthIndex = 0
 let mutable tMatch = true
 try 
 while ( tSmallHeightIndex < tSmallHeight - 1 ) && tMatch do
 while ( tSmallWidthIndex < tSmallWidth - 1 ) && tMatch do
 let tLargeCurrentValue = tLargeArray.[tHeightIndex + tSmallHeightIndex].[tWidthIndex + tSmallWidthIndex]
 let tSmallCurrentValue = tSmallArray.[tSmallHeightIndex].[tSmallWidthIndex]
 if tSmallCurrentValue = tLargeCurrentValue then
 tSmallWidthIndex <- tSmallWidthIndex + 1 
 else
 tMatch <- false
 tSmallWidthIndex <- 0
 tSmallHeightIndex <- tSmallHeightIndex + 1
 tMatch
 with
 | _ -> false
namespace FsharpImaging
open System
open System.Drawing
open System.Drawing.Imaging
open System.Runtime.InteropServices
open MathAlgorithms
module ImageFunctions = 
 let LoadBitmapIntoArray (pBitmap:Bitmap) =
 let tBitmapData = pBitmap.LockBits( Rectangle(Point.Empty, pBitmap.Size), 
 ImageLockMode.ReadOnly, 
 PixelFormat.Format24bppRgb ) 
 let tImageArrayLength = Math.Abs(tBitmapData.Stride) * pBitmap.Height
 let tImageDataArray = Array.zeroCreate<byte> tImageArrayLength
 
 Marshal.Copy(tBitmapData.Scan0, tImageDataArray, 0, tImageArrayLength)
 pBitmap.UnlockBits(tBitmapData)
 ( pBitmap.Width, pBitmap.Height, tBitmapData.Stride ), tImageDataArray
 // Notes:
 // Image pixel data is stored BGR ( blue green red )
 // Image data is padded to be divisible by 4 (int32 width)
 
 let Transform2D ( (pDimension:int*int*int), (pArray:byte[]) ) = 
 let tWidth, tHeight, tStride = pDimension
 [|
 for tHeightIndex in 0 .. ( tHeight - 1 ) do
 let tStart = tHeightIndex * tStride
 let tFinish = ( tStart + tWidth * 3 ) - 1
 yield [| 
 for tWidthIndex in tStart .. 3 .. tFinish do
 yield ( pArray.[tWidthIndex]
 , pArray.[tWidthIndex + 1] 
 , pArray.[tWidthIndex + 2] )
 |]
 |]
module ImageSearch = 
 open ImageFunctions
 let SearchBitmap (pSmallBitmap:Bitmap) (pLargeBitmap:Bitmap) = 
 
 let tSmallArray = Transform2D <| LoadBitmapIntoArray pSmallBitmap 
 let tLargeArray = Transform2D <| LoadBitmapIntoArray pLargeBitmap
 
 let tSearchWidth = pLargeBitmap.Width - pSmallBitmap.Width
 let tSearchHeight = pLargeBitmap.Height - pSmallBitmap.Height
 let mutable tHeightIndex = 0
 let mutable tWidthIndex = 0
 let mutable tMatch = false
 let mutable tContinue = true
 while ( tHeightIndex < tSearchHeight - 1 ) && tContinue do
 while ( tWidthIndex < tSearchWidth - 1 ) && tContinue do
 let tCurrentValue = tLargeArray.[tHeightIndex].[tWidthIndex]
 let tFirstSmallPixel = tSmallArray.[0].[0]
 if tCurrentValue = tFirstSmallPixel then
 tMatch <- ArrayFunctions.SearchSubset tSmallArray tLargeArray ( tHeightIndex, tWidthIndex )
 if tMatch then tContinue <- false
 if tMatch = false && tContinue = true then
 tWidthIndex <- tWidthIndex + 1
 if tMatch = false && tContinue = true then
 tWidthIndex <- 0 // Reset to search next row
 tHeightIndex <- tHeightIndex + 1
 tMatch, tWidthIndex, tHeightIndex
namespace MainProgram
open System.Drawing
open System.Drawing.Imaging
open System.Diagnostics
open FsharpImaging
module Main = 
 [<EntryPoint>]
 let main (args:string[]) = 
 
 use tSmallBitmap = new Bitmap("searchimage.bmp")
 use tLargeBitmap = new Bitmap("containingimage.bmp")
 let tSuccess, xCoord, yCoord = ImageSearch.SearchBitmap tSmallBitmap tLargeBitmap
 // Must return from function
 0
added 527 characters in body
Source Link
Ken
  • 653
  • 4
  • 12

I've been doing some testing and discovered (and have now fixed) a few logical bugs. I'm testing using two images where I know one is located inside the other (and have verified this using another algorithm) but it appears this code currently can not find matches, though it appears correct.

open System
open System.Drawing
open System.Drawing.Imaging
open System.Runtime.InteropServices
module ImageSearch = 
 let LoadBitmapIntoArray (pBitmap:Bitmap) =
 let tBitmapData = pBitmap.LockBits( Rectangle(Point.Empty, pBitmap.Size), 
 ImageLockMode.ReadOnly, 
 PixelFormat.Format24bppRgb ) 
 // Bitmap.Stride can be negative to indicate different orientation of the bitmap
 let tImageArrayLength = Math.Abs(tBitmapData.Stride) * pBitmap.Height
 let tImageDataArray = Array.zeroCreate<byte> tImageArrayLength
 
 // Marshal.Copy(tImageDataArray, 0, tBitmapData.Scan0, tImageArrayLength)
 Marshal.Copy(tBitmapData.Scan0, tImageDataArray, 0, tImageArrayLength)
 pBitmap.UnlockBits(tBitmapData)
 pBitmap.Width, tImageDataArray
 let Transform2D ( (pArrayWidth:int), (pArray:byte[]) ) = 
 let tHeight = pArray.Length / ( pArrayWidth * 3 ) // 3 bytes per RGB
 [|
 for tHeightIndex in 0 .. tHeight - 1 do
 let tStart = tHeightIndex * ( pArrayWidth * 3 - 1 )
 let tFinish = tStart + pArrayWidth * 3 - 1 
 yield [| 
 for tWidthIndex in tStart .. 3 .. tFinish do
 yield ( pArray.[tWidthIndex]
 , pArray.[tWidthIndex + 1] 
 , pArray.[tWidthIndex + 2] )
 |]
 |]
 let SearchSubset (tSmallArray:(byte * byte * byte)[][]) (tLargeArray:(byte * byte * byte)[][]) (pCoordinate:(int * int)) =
 let tSmallHeight = tSmallArray.Length
 let tSmallWidth = tSmallArray.[0].Length
 let tHeightIndex = fst pCoordinate
 let tWidthIndex = snd pCoordinate
 let mutable tSmallHeightIndex = 0
 let mutable tSmallWidthIndex = 0
 let mutable tMatch = true
 try 
 while ( tSmallHeightIndex < tSmallHeight - 1 ) && tMatch do
 while ( tSmallWidthIndex < tSmallWidth - 1 ) && tMatch do
 let tLargeCurrentValue = tLargeArray.[tHeightIndex + tSmallHeightIndex].[tWidthIndex + tSmallWidthIndex]
 let tSmallCurrentValue = tSmallArray.[tSmallHeightIndex].[tSmallWidthIndex]
 if tSmallCurrentValue = tLargeCurrentValue then
 tSmallHeightIndex <- tSmallHeightIndex + 1
 tSmallWidthIndex <- tSmallWidthIndex + 1 
 else
 tMatch <- false
 tSmallHeightIndex <- tSmallHeightIndex + 1

 tMatch
 with
 | _ -> false
 let SearchBitmap (pSmallBitmap:Bitmap) (pLargeBitmap:Bitmap) = 
 
 let tSmallArray = Transform2D <| LoadBitmapIntoArray pSmallBitmap 
 let tLargeArray = Transform2D <| LoadBitmapIntoArray pLargeBitmap
 
 let tSearchWidth = pLargeBitmap.Width - pSmallBitmap.Width
 let tSearchHeight = pLargeBitmap.Height - pSmallBitmap.Height
 let mutable tHeightIndex = 0
 let mutable tWidthIndex = 0
 let mutable tMatch = false
 let mutable tContinue = true
 while ( tHeightIndex < tSearchHeight - 1 ) && tMatchtContinue do
 while ( tWidthIndex < tSearchWidth - 1 ) && tMatchtContinue do
 let tCurrentValue = tLargeArray.[tHeightIndex].[tWidthIndex]
 let tFirstSmallPixel = tSmallArray.[0].[0]
 if tCurrentValue = tFirstSmallPixel then
 tMatch <- SearchSubset tSmallArray tLargeArray ( tHeightIndex, tWidthIndex )
 if tMatch then tContinue <- false
 else
 if tMatch = false tHeightIndex&& <-tContinue tHeightIndex= +true 1then
 tWidthIndex <- tWidthIndex + 1
 if tMatch, = false && tContinue = true then
  tHeightIndex <- tHeightIndex + 1
 tMatch, tWidthIndex, tHeightIndex
 [<EntryPoint>]
 let main (args:string[]) = 
 
 letuse tSmallBitmap = new Bitmap("testimage1"testimage2.jpg"bmp")
 letuse tLargeBitmap = new Bitmap("testimage2"testimage1.jpg"bmp")
 let tSuccess, xCoord, yCoord = SearchBitmap tSmallBitmap tLargeBitmap
 // General plan for looping
 // - Split single array for small image into 2d array of arrays
 // - Split single array for large image into 2d array of arrays
 // - Iterate through each array in large array looking for first value from small array
 // - If first value is found, then check for complete row
 // - If row is complete then check for second row (and so on)
 // - Stop searching horizontally when remaining pixels are smaller than search image width
 // - Stop searching vertically when remaining pixels are smaller than search image height 
 // Must return from function
 0
open System
open System.Drawing
open System.Drawing.Imaging
open System.Runtime.InteropServices
module ImageSearch = 
 let LoadBitmapIntoArray (pBitmap:Bitmap) =
 let tBitmapData = pBitmap.LockBits( Rectangle(Point.Empty, pBitmap.Size), 
 ImageLockMode.ReadOnly, 
 PixelFormat.Format24bppRgb ) 
 // Bitmap.Stride can be negative to indicate different orientation of the bitmap
 let tImageArrayLength = Math.Abs(tBitmapData.Stride) * pBitmap.Height
 let tImageDataArray = Array.zeroCreate<byte> tImageArrayLength
 
 Marshal.Copy(tImageDataArray, 0, tBitmapData.Scan0, tImageArrayLength)
 pBitmap.UnlockBits(tBitmapData)
 pBitmap.Width, tImageDataArray
 let Transform2D ( (pArrayWidth:int), (pArray:byte[]) ) = 
 let tHeight = pArray.Length / ( pArrayWidth * 3 ) // 3 bytes per RGB
 [|
 for tHeightIndex in 0 .. tHeight - 1 do
 let tStart = tHeightIndex * pArrayWidth
 let tFinish = tStart + pArrayWidth - 1 
 yield [| 
 for tWidthIndex in tStart .. 3 .. tFinish do
 yield ( pArray.[tWidthIndex]
 , pArray.[tWidthIndex + 1] 
 , pArray.[tWidthIndex + 2] )
 |]
 |]
 let SearchSubset (tSmallArray:(byte * byte * byte)[][]) (tLargeArray:(byte * byte * byte)[][]) (pCoordinate:(int * int)) =
 let tSmallHeight = tSmallArray.Length
 let tSmallWidth = tSmallArray.[0].Length
 let tHeightIndex = fst pCoordinate
 let tWidthIndex = snd pCoordinate
 let mutable tSmallHeightIndex = 0
 let mutable tSmallWidthIndex = 0
 let mutable tMatch = true
 try 
 while ( tSmallHeightIndex < tSmallHeight ) && tMatch do
 while ( tSmallWidthIndex < tSmallWidth ) && tMatch do
 let tLargeCurrentValue = tLargeArray.[tHeightIndex + tSmallHeightIndex].[tWidthIndex + tSmallWidthIndex]
 let tSmallCurrentValue = tSmallArray.[tSmallHeightIndex].[tSmallWidthIndex]
 if tSmallCurrentValue = tLargeCurrentValue then
 tSmallHeightIndex <- tSmallHeightIndex + 1
 tSmallWidthIndex <- tSmallWidthIndex + 1 
 else
 tMatch <- false
 tMatch
 with
 | _ -> false
 let SearchBitmap (pSmallBitmap:Bitmap) (pLargeBitmap:Bitmap) = 
 
 let tSmallArray = Transform2D <| LoadBitmapIntoArray pSmallBitmap 
 let tLargeArray = Transform2D <| LoadBitmapIntoArray pLargeBitmap
 
 let tSearchWidth = pLargeBitmap.Width - pSmallBitmap.Width
 let tSearchHeight = pLargeBitmap.Height - pSmallBitmap.Height
 let mutable tHeightIndex = 0
 let mutable tWidthIndex = 0
 let mutable tMatch = false
 let mutable tContinue = true
 while tHeightIndex < tSearchHeight && tMatch do
 while tWidthIndex < tSearchWidth && tMatch do
 let tCurrentValue = tLargeArray.[tHeightIndex].[tWidthIndex]
 let tFirstSmallPixel = tSmallArray.[0].[0]
 if tCurrentValue = tFirstSmallPixel then
 tMatch <- SearchSubset tSmallArray tLargeArray ( tHeightIndex, tWidthIndex )
 if tMatch then tContinue <- false
 else
 tHeightIndex <- tHeightIndex + 1
 tWidthIndex <- tWidthIndex + 1
 tMatch, tHeightIndex, tWidthIndex
 [<EntryPoint>]
 let main (args:string[]) = 
 
 let tSmallBitmap = new Bitmap("testimage1.jpg")
 let tLargeBitmap = new Bitmap("testimage2.jpg")
 let tSuccess, xCoord, yCoord = SearchBitmap tSmallBitmap tLargeBitmap
 // General plan for looping
 // - Split single array for small image into 2d array of arrays
 // - Split single array for large image into 2d array of arrays
 // - Iterate through each array in large array looking for first value from small array
 // - If first value is found, then check for complete row
 // - If row is complete then check for second row (and so on)
 // - Stop searching horizontally when remaining pixels are smaller than search image width
 // - Stop searching vertically when remaining pixels are smaller than search image height 
 // Must return from function
 0

I've been doing some testing and discovered (and have now fixed) a few logical bugs. I'm testing using two images where I know one is located inside the other (and have verified this using another algorithm) but it appears this code currently can not find matches, though it appears correct.

open System
open System.Drawing
open System.Drawing.Imaging
open System.Runtime.InteropServices
module ImageSearch = 
 let LoadBitmapIntoArray (pBitmap:Bitmap) =
 let tBitmapData = pBitmap.LockBits( Rectangle(Point.Empty, pBitmap.Size), 
 ImageLockMode.ReadOnly, 
 PixelFormat.Format24bppRgb ) 
 // Bitmap.Stride can be negative to indicate different orientation of the bitmap
 let tImageArrayLength = Math.Abs(tBitmapData.Stride) * pBitmap.Height
 let tImageDataArray = Array.zeroCreate<byte> tImageArrayLength
 
 // Marshal.Copy(tImageDataArray, 0, tBitmapData.Scan0, tImageArrayLength)
 Marshal.Copy(tBitmapData.Scan0, tImageDataArray, 0, tImageArrayLength)
 pBitmap.UnlockBits(tBitmapData)
 pBitmap.Width, tImageDataArray
 let Transform2D ( (pArrayWidth:int), (pArray:byte[]) ) = 
 let tHeight = pArray.Length / ( pArrayWidth * 3 ) // 3 bytes per RGB
 [|
 for tHeightIndex in 0 .. tHeight - 1 do
 let tStart = tHeightIndex * ( pArrayWidth * 3 - 1 )
 let tFinish = tStart + pArrayWidth * 3 - 1 
 yield [| 
 for tWidthIndex in tStart .. 3 .. tFinish do
 yield ( pArray.[tWidthIndex]
 , pArray.[tWidthIndex + 1] 
 , pArray.[tWidthIndex + 2] )
 |]
 |]
 let SearchSubset (tSmallArray:(byte * byte * byte)[][]) (tLargeArray:(byte * byte * byte)[][]) (pCoordinate:(int * int)) =
 let tSmallHeight = tSmallArray.Length
 let tSmallWidth = tSmallArray.[0].Length
 let tHeightIndex = fst pCoordinate
 let tWidthIndex = snd pCoordinate
 let mutable tSmallHeightIndex = 0
 let mutable tSmallWidthIndex = 0
 let mutable tMatch = true
 try 
 while ( tSmallHeightIndex < tSmallHeight - 1 ) && tMatch do
 while ( tSmallWidthIndex < tSmallWidth - 1 ) && tMatch do
 let tLargeCurrentValue = tLargeArray.[tHeightIndex + tSmallHeightIndex].[tWidthIndex + tSmallWidthIndex]
 let tSmallCurrentValue = tSmallArray.[tSmallHeightIndex].[tSmallWidthIndex]
 if tSmallCurrentValue = tLargeCurrentValue then
 tSmallWidthIndex <- tSmallWidthIndex + 1 
 else
 tMatch <- false
 tSmallHeightIndex <- tSmallHeightIndex + 1

 tMatch
 with
 | _ -> false
 let SearchBitmap (pSmallBitmap:Bitmap) (pLargeBitmap:Bitmap) = 
 
 let tSmallArray = Transform2D <| LoadBitmapIntoArray pSmallBitmap 
 let tLargeArray = Transform2D <| LoadBitmapIntoArray pLargeBitmap
 
 let tSearchWidth = pLargeBitmap.Width - pSmallBitmap.Width
 let tSearchHeight = pLargeBitmap.Height - pSmallBitmap.Height
 let mutable tHeightIndex = 0
 let mutable tWidthIndex = 0
 let mutable tMatch = false
 let mutable tContinue = true
 while ( tHeightIndex < tSearchHeight - 1 ) && tContinue do
 while ( tWidthIndex < tSearchWidth - 1 ) && tContinue do
 let tCurrentValue = tLargeArray.[tHeightIndex].[tWidthIndex]
 let tFirstSmallPixel = tSmallArray.[0].[0]
 if tCurrentValue = tFirstSmallPixel then
 tMatch <- SearchSubset tSmallArray tLargeArray ( tHeightIndex, tWidthIndex )
 if tMatch then tContinue <- false
 if tMatch = false && tContinue = true then
 tWidthIndex <- tWidthIndex + 1
 if tMatch = false && tContinue = true then
  tHeightIndex <- tHeightIndex + 1
 tMatch, tWidthIndex, tHeightIndex
 [<EntryPoint>]
 let main (args:string[]) = 
 
 use tSmallBitmap = new Bitmap("testimage2.bmp")
 use tLargeBitmap = new Bitmap("testimage1.bmp")
 let tSuccess, xCoord, yCoord = SearchBitmap tSmallBitmap tLargeBitmap
 // General plan for looping
 // - Split single array for small image into 2d array of arrays
 // - Split single array for large image into 2d array of arrays
 // - Iterate through each array in large array looking for first value from small array
 // - If first value is found, then check for complete row
 // - If row is complete then check for second row (and so on)
 // - Stop searching horizontally when remaining pixels are smaller than search image width
 // - Stop searching vertically when remaining pixels are smaller than search image height 
 // Must return from function
 0
Source Link
Ken
  • 653
  • 4
  • 12
Loading
lang-ml

AltStyle によって変換されたページ (->オリジナル) /