efficient way to compare 2 images?
#51
(11-19-2022, 11:59 PM)SMcNeill Wrote:
Code: (Select All)
Const FALSE = 0
Const TRUE = Not FALSE

Type CompareType
    r1 As Long
    g1 As Long
    b1 As Long
    a1 As Long
    r2 As Long
    g2 As Long
    b2 As Long
    a2 As Long
End Type

ReDim arrCompare(-1) As CompareType
Dim As _Unsigned Long p1
Dim As _Unsigned Long p2
Dim image1&
Dim image2&
Dim total$
Dim rgb1$
Dim rgb2$
Dim r1&, g1&, b1&, a1&
Dim r2&, g2&, b2&, a2&

' INITIALIZE
Screen _NewImage(1024, 768, 32): _Dest 0: Cls , cBlack
image1& = _NewImage(100, 100, 32)
image2& = _NewImage(100, 100, 32)


_DontBlend


' READ TEST COLORS
Restore TestData
For iLoop% = 1 To 1000
    Read r1&: Read g1&: Read b1&: Read a1&
    Read r2&: Read g2&: Read b2&: Read a2&

    Print _Trim$(Str$(r1&)) + ", " + _Trim$(Str$(g1&)) + ", " + _Trim$(Str$(b1&)) + ", " + _Trim$(Str$(a1&))
    Print _Trim$(Str$(r2&)) + ", " + _Trim$(Str$(g2&)) + ", " + _Trim$(Str$(b2&)) + ", " + _Trim$(Str$(a2&))

    If r1& = -2 Then Exit For

    ReDim _Preserve arrCompare(UBound(arrCompare) + 1) As CompareType
    arrCompare(UBound(arrCompare)).r1 = r1&
    arrCompare(UBound(arrCompare)).g1 = g1&
    arrCompare(UBound(arrCompare)).b1 = b1&
    arrCompare(UBound(arrCompare)).a1 = a1&
    arrCompare(UBound(arrCompare)).r2 = r2&
    arrCompare(UBound(arrCompare)).g2 = g2&
    arrCompare(UBound(arrCompare)).b2 = b2&
    arrCompare(UBound(arrCompare)).a2 = a2&

    'print "UBOUND(arrCompare) = " + _Trim$(Str$(UBOUND(arrCompare)))
Next iLoop%

'print "LBOUND(arrCompare) = " + _Trim$(Str$(LBOUND(arrCompare)))
'print "UBOUND(arrCompare) = " + _Trim$(Str$(UBOUND(arrCompare)))
'print "Finished reading data. Press any key to begin testing." : sleep

TestData:
' -1 means no alpha channel, -2 means end of data
Data 255,0,0,-1
Data 0,0,255,-1
Data 128,128,128,-1
Data 64,64,64,-1
Data 0,255,255,-1
Data 0,254,254,-1

Data 255,0,0,255
Data 255,0,0,-1
Data 255,0,0,254
Data 255,0,0,-1
Data 255,0,0,253
Data 255,0,0,-1
Data 255,0,0,255
Data 255,0,0,254
Data 255,0,0,255
Data 255,0,0,253
Data 255,0,0,254
Data 255,0,0,253
Data 255,0,0,254
Data 255,0,0,252
Data 255,0,0,253
Data 255,0,0,252
Data 255,0,0,253
Data 255,0,0,251
Data -2,-2,-2,-2
Data -2,-2,-2,-2
Data -2,-2,-2,-2
Data -2,-2,-2,-2

' TEST WITH VARIOUS COMBINATIONS OF ALPHA VALUES AND NO ALPHA VALUES
total$ = " of " + _Trim$(Str$(UBound(arrCompare)))
For iLoop% = LBound(arrCompare) To UBound(arrCompare)
    ' GET COLOR #1
    If arrCompare(iLoop%).a1 < 0 Then
        p1 = _RGB32(arrCompare(iLoop%).r1, arrCompare(iLoop%).g1, arrCompare(iLoop%).b1)
        rgb1$ = "_RGB32(" + _Trim$(Str$(arrCompare(iLoop%).r1)) + ", " + _Trim$(Str$(arrCompare(iLoop%).g1)) + ", " + _Trim$(Str$(arrCompare(iLoop%).b1)) + ")"
    Else
        p1 = _RGB32(arrCompare(iLoop%).r1, arrCompare(iLoop%).g1, arrCompare(iLoop%).b1, arrCompare(iLoop%).a1)
        rgb1$ = "_RGB32(" + _Trim$(Str$(arrCompare(iLoop%).r1)) + ", " + _Trim$(Str$(arrCompare(iLoop%).g1)) + ", " + _Trim$(Str$(arrCompare(iLoop%).b1)) + ", " + _Trim$(Str$(arrCompare(iLoop%).a1)) + ")"
    End If
    _Dest image1&
    Line (1, 1)-(100, 100), p1, BF ' Draw a solid box
    _Source image1&
    p1 = Point(50, 50)
    r1& = _Red32(p1): g1& = _Green32(p1): b1& = _Blue32(p1): a1& = _Alpha32(p1)
    Circle (50, 50), 5

    ' GET COLOR #2
    If arrCompare(iLoop%).a2 < 0 Then
        p2 = _RGB32(arrCompare(iLoop%).r2, arrCompare(iLoop%).g2, arrCompare(iLoop%).b2)
        rgb2$ = "_RGB32(" + _Trim$(Str$(arrCompare(iLoop%).r2)) + ", " + _Trim$(Str$(arrCompare(iLoop%).g2)) + ", " + _Trim$(Str$(arrCompare(iLoop%).b2)) + ")"
    Else
        p2 = _RGB32(arrCompare(iLoop%).r2, arrCompare(iLoop%).g2, arrCompare(iLoop%).b2, arrCompare(iLoop%).a2)
        rgb2$ = "_RGB32(" + _Trim$(Str$(arrCompare(iLoop%).r2)) + ", " + _Trim$(Str$(arrCompare(iLoop%).g2)) + ", " + _Trim$(Str$(arrCompare(iLoop%).b2)) + ", " + _Trim$(Str$(arrCompare(iLoop%).a2)) + ")"
    End If
    _Dest image2&
    Line (1, 1)-(100, 100), p2, BF ' Draw a solid box
    _Source image2&
    p2 = Point(50, 50)
    r2& = _Red32(p2): g2& = _Green32(p2): b2& = _Blue32(p2): a2& = _Alpha32(p2)
    Circle (50, 50), 5

    ' SHOW RESULTS
    _Dest 0: Cls , cBlack

    Locate 2, 1: Print "Compare image alpha values, test " + _Trim$(Str$(iLoop%)) + total$

    Locate 10, 3: Print "image1&:";
    Locate 10, 28: Print "image2&:";
    _PutImage (100, 100), image1&, 0
    _PutImage (300, 100), image2&, 0

    Locate 14, 1
    Print "Comparing " + rgb1$ + _
        " _Source image1& : p1 = Point(50, 50) = " + _Trim$(Str$(p1%)) + _
        "_RED=" + _Trim$(Str$(r1&)) + ", " + "_GREEN=" + _Trim$(Str$(g1&)) + ", " + "_BLUE=" + _Trim$(Str$(b1&)) + ", " + "_ALPHA=" + _Trim$(Str$(a1&))
    Print "    with " + rgb2$ + _
        " _Source image2& : p2 = Point(50, 50) = " + _Trim$(Str$(p2%)) + _
        "_RED=" + _Trim$(Str$(r2&)) + ", " + "_GREEN=" + _Trim$(Str$(g2&)) + ", " + "_BLUE=" + _Trim$(Str$(b2&)) + ", " + "_ALPHA=" + _Trim$(Str$(a2&))
    Print

    ' comparing points
    Print "Compare images with Point(x, y):"
    If p1 = p2 Then
        Print "No difference detected: I'm a monkey's uncle."
    Else
        Print "Different: Ha!"
    End If
    Print

    ' bplus's function
    Print "Compare images with Function CompareImages&:"
    If CompareImages&(image1&, image2&) = TRUE Then
        Print "No difference detected: I'm a monkey's uncle."
    Else
        Print "Different: Ha!"
    End If
    Print

    ' bplus's function prettified by madsci
    Print "Compare images with Function CompareImagesBPlus%:"
    If CompareImagesBPlus%(image1&, image2&) = TRUE Then
        Print "No difference detected: I'm a monkey's uncle."
    Else
        Print "Different: Ha!"
    End If
    Print

    If iLoop% < UBound(arrCompare) Then Print "Press any key to continue": Sleep

    _KeyClear
Next iLoop%

' cleanup
If image1& < -1 Then _FreeImage image1&
If image2& < -1 Then _FreeImage image2&

' done
Print "That concludes our test. Press any key to exit..."
Sleep
System

'DrawRectSolid x%, y%, width%, height%, fgColor~&
Sub DrawRectSolid (iX As Integer, iY As Integer, iSizeW As Integer, iSizeH As Integer, fgColor As _Unsigned Long)
    Line (iX, iY)-(iX + (iSizeW - 1), iY + (iSizeH - 1)), fgColor, BF ' Draw a solid rectangle
End Sub ' DrawRectSolid

' /////////////////////////////////////////////////////////////////////////////
' FROM: bplus
' https://staging.qb64phoenix.com/showthread.php?tid=1151&pid=10262#pid10262
' Don't know what you are doing but:
' Point can distinguish between 2 alpha settings!

Sub TestPointAlpha
    Screen _NewImage(800, 600, 32)
    Line (100, 100)-Step(100, 100), _RGB32(255, 0, 0, 236), BF
    Line (300, 100)-Step(100, 100), _RGB32(255, 0, 0, 237), BF
    If Point(150, 150) = Point(350, 150) Then Print "I'm a monkey's uncle." Else Print "Ha!"
    Circle (150, 150), 5
    Circle (350, 150), 5
End Sub ' TestPointAlpha

' /////////////////////////////////////////////////////////////////////////////
' FROM: bplus
' https://staging.qb64phoenix.com/showthread.php?tid=1151&pid=10242#pid10242
' Well my idea didn't take so long for one compare, just blink and there's your answer:
' Not nearly as quick as memory methods though.
' b = b + ...

Function CompareImages& (handle1 As Long, handle2 As Long)
    Dim As _Unsigned Long p1
    For y = 0 To _Height(handle1) - 1
        For x = 0 To _Width(handle1) - 1
            _Source handle1
            p1 = Point(x, y)
            _Source handle2
            If Point(x, y) <> p1 Then Exit Function
        Next
    Next
    CompareImages& = -1
End Function

Function CompareImagesBPlus% (handle1 As Long, handle2 As Long)
    Dim bResult%: bResult% = TRUE
    Dim p1 As _Unsigned Long
    Dim y, x As Integer
    Dim bFinished%: bFinished% = FALSE
    For y = 0 To _Height(handle1) - 1
        For x = 0 To _Width(handle1) - 1
            _Source handle1
            p1 = Point(x, y)
            _Source handle2
            If Point(x, y) <> p1 Then
                bResult% = FALSE
                bFinished% = FALSE
                Exit For
            End If
        Next x
        If bFinished% = TRUE Then Exit For
    Next y
    CompareImagesBPlus% = bResult%
End Function ' CompareImagesBPlus%


The issue is really rather simple -- all your values that you're comparing *ARE* exactly the same.

Let me ask you guys a simple question and then you tell me what happens:  What happens when you put a 50 alpha image onto an already existing image?

Say for example, you normally have a pure black screen: 255 alpha, 0 red, 0 green, 0 blue.
Now, you decide to put a faded white color onto that screen:  50 alpha, 255 red, 255 green, 255 blue.

What is the final result that you get?  Does it just add everything together and then divide by two?   150 alpha, 150 red, 150 green, 150 blue??

Think about it....




If you don't know, and don't want to give it a try to test, I'll go ahead and give you the answer:

When two colors blend together, the end result is a color with 255 alpha.  Poll your display screen at any time you want, and check the alpha levels on it.  255.  255. 255. 255.   Blend whatever you want onto it.  255. 255. 255.   Toss full alpha at it... 255. 255. 255.  Toss zero alpha at it.... 255. 255. 255.   Toss 125 alpha at it....  255. 255. 255.  (Those 255's are your alpha levels.)

As long as blending is on, your display is always going to blend to 255 alpha.   Your alpha check is telling you that all the screen colors have the same level of alpha with your display because they do!

Don't want that blending to blend everything to 255 alpha?

_DONTBLEND

Aha!!!!!!! 

Thanks for catching that!! 

(outside getting ready to grill, cannot try code on pc now!)
Reply
#52
(11-20-2022, 12:04 AM)SMcNeill Wrote: bplus's demo, modified to just check alpha levels and not colors themselves:

Code: (Select All)
Screen _NewImage(800, 600, 32)
Dim i As Long
For i = 0 To 255
    Cls
    Line (100, 100)-Step(100, 100), _RGB32(255, 0, 0, i), BF
    Line (300, 100)-Step(100, 100), _RGB32(255, 0, 0), BF
    If _Alpha32(Point(150, 150)) = _Alpha32(Point(350, 150)) Then
        Print "When alpha ="; i; " have NO difference, zzz ..."
    Else
        Print "When alpha ="; i; " have difference, zzz ..."
    End If
    Print Hex$(Point(150, 150)), Hex$(Point(350, 150))
    Sleep
Next


Modified to print the actual color values that are on the screen for you.

OK it is a bit of a shocker to see alpha levels stay the same.

But as you can see the red levels are changing with the blend and the whole point my part in this thread was to detect point differences in color which we have until alpha = 255 same as a solid color.

So my question to @SMcneill is are you saying POINT() can't be used to detect differences between 2 images?
b = b + ...
Reply
#53
@bplus I'm saying there's NO reliable test once you start blending two images together!

[b]madscijr [/b]asked why his code wasn't working -- it's because he was blending colors on a black background.  In his code, these two are a perfect match:

LINE (100,100)-(300,300), _RGB32(255,0,0), BF
LINE (300,100)-(500,300), _RGBA32(255,0,0,254), BF

Now, is 255 alpha and 254 alpha a color match?   Obviously not!

But once they're blended onto a 255 alpha image?  How different are they??

Apparently they're not different at all, according to his tests.  (I'd guess full red -- 255, at 254 alpha, does some basic type math:  255 * 254/255 = 254.whatever... which then gets rounded up to the nearest whole value of 255.)

So in this case, *once the colors are blended onto a second screen*, they're no longer different.  They're so close alike that when they blend, they become the same color.

Which is why I said his answer was to _DONTBLEND those colors and then compare them.



It's not that you can't use POINT to compare values.  It's that you can't use *anything* to successfully compare initial values after you blend them.

Think of it as mixing black and white and making gray.
Then you mix dark midnight-gray and ivory, which makes the same gray.

Now, can you say that the first two colors are the same as the second two colors, just because the end result matches??
Reply
#54
Quote:Now, can you say that the first two colors are the same as the second two colors, just because the end result matches??


I would say if the two Point values match up then they are the same. Obviously we can't go by a single _Red32, _Green32, _Blue32, _Alpha32 value because of blending but if all of them match then they must be same color because the total color value must be unique.

No you can't predict how the colors were made from mixes, how did you get to 10? 5+5 or 3+7 or 1 +9 but 10 = 10
b = b + ...
Reply
#55
(11-20-2022, 01:07 AM)SMcNeill Wrote: @bplus I'm saying there's NO reliable test once you start blending two images together!

[b]madscijr [/b]asked why his code wasn't working -- it's because he was blending colors on a black background.  In his code, these two are a perfect match:

LINE (100,100)-(300,300), _RGB32(255,0,0), BF
LINE (300,100)-(500,300), _RGBA32(255,0,0,254), BF

Now, is 255 alpha and 254 alpha a color match?   Obviously not!

But once they're blended onto a 255 alpha image?  How different are they??

Yeah it just comes down to my ignorance that you need DONTBLEND for putimage to overwrite the image. I learned something new.
Reply
#56
Couldn't you just:
Put image1 on a screen
Put image2 on the screen with a XOR  

Any pixels that aren't the background color will be pixels that are different in the two images.  
Count them (well, have a program do that ).  How many pixels need to be different before you can make a decision on comparison is up to you.
Reply
#57
(11-20-2022, 04:42 AM)James D Jarvis Wrote: Couldn't you just:
Put image1 on a screen
Put image2 on the screen with a XOR  

Any pixels that aren't the background color will be pixels that are different in the two images.  
Count them (well, have a program do that ).  How many pixels need to be different before you can make a decision on comparison is up to you.

That's kind of brilliant, but how do you put an image with XOR??
Reply
#58
(11-20-2022, 05:28 AM)madscijr Wrote: That's kind of brilliant, but how do you put an image with XOR??
Must do it with the old "PUT" command, not with "_PUTIMAGE", which is more limiting and requires the programmer to create a large buffer for the image, instead of "managing" with a long-integer handle and extracting a small section of a picture perhaps too large to fit into the screen.

Cannot flip nor stretch with "PUT"; however, "_PUTIMAGE" could only replicate what's in a graphics buffer, it's programmed like that for speed.

Maybe it is better to use "AND" attribute instead with "PUT". Then the images would have to be closely related, with one being the "mask" of the other. Something like having full-white pixels in order to preserve any element of the "busier" image, and jet-black to delete.

From:

https://qb64phoenix.com/qb64wiki/index.p...statement)

Quote:If no color action is listed after the image array, the action will be assumed to be the default XOR.
Reply
#59
(11-20-2022, 05:28 AM)madscijr Wrote:
(11-20-2022, 04:42 AM)James D Jarvis Wrote: Couldn't you just:
Put image1 on a screen
Put image2 on the screen with a XOR  

Any pixels that aren't the background color will be pixels that are different in the two images.  
Count them (well, have a program do that ).  How many pixels need to be different before you can make a decision on comparison is up to you.

That's kind of brilliant, but how do you put an image with XOR??    

Sorry for late reply, I missed the question.  As  mnrvovrfc just use PUT.  There are of course limitations because you can't rescale as quickly as you can with _putimage.
PUT (graphics statement) - QB64 Phoenix Edition Wiki
Reply
#60
(11-18-2022, 09:34 PM)SMcNeill Wrote: An example with 720p images at play:

Code: (Select All)
Randomize Timer

Screen _NewImage(1280, 720, 32)

'let's make this an unique and pretty image!
For i = 1 To 100
    Line (Rnd * _Width, Rnd * _Height)-(Rnd * width, Rnd * _Height), &HFF000000 + Rnd * &HFFFFFF, BF
Next

image2 = _CopyImage(0) 'identical copies for testing
image3 = _CopyImage(0) 'identical copy...  BUT
_Dest image3
PSet (Rnd * _Width, Rnd * _Height), &HFF000000 + Rnd * &HFFFFFF 'We've just tweaked it so that there's no way in hell it's the same as the other two now!
_Dest 0 'image3 is EXACTLY one pixel different from the other two.  Can we detect that?
image4 = _CopyImage(0) 'an identical copy once again, because 0 will change once we print the results

result1 = CompareImages(0, image2)
result2 = CompareImages(0, image3)
result3 = CompareImages(image2, image3)

Print "Current Screen and Image 1 Compare:  "; result1
Print "Current Screen and Image 2 Compare:  "; result2
Print "Image1 and Image 2 Compare        :  "; result3

Print
Print "Press <ANY KEY> for a speed test!"
Sleep

t# = Timer
Limit = 1000
For i = 1 To Limit
    result = CompareImages(image2, image3)
    result = CompareImages(image2, image4)
Next
Print
Print Using "####.####### seconds to do"; Timer - t#;
Print Limit * 2; "comparisons."


Function CompareImages (handle1 As Long, handle2 As Long)
    $Checking:Off
    Static m(1) As _MEM
    Dim s(1) As String
    m(0) = _MemImage(handle1): m(1) = _MemImage(handle2)
    If m(0).SIZE <> m(1).SIZE Then Exit Function 'not identical
    If m(0).ELEMENTSIZE <> m(1).ELEMENTSIZE Then Exit Function 'not identical
    s(0) = Space$(m(0).SIZE): s(1) = Space$(m(1).SIZE)
    _MemGet m(0), m(0).OFFSET, s(0): _MemGet m(1), m(1).OFFSET, s(1)
    If s(0) = s(1) Then CompareImages = -1
    $Checking:On
End Function

This function is going into my tool box! I ran across a need today to compare many images generated within code, not from files. I remembered this thread. Steve, this code works perfectly. Thank you for sharing.
Reply




Users browsing this thread: 25 Guest(s)