Jump to content

Stereograms!


andybiochem
 Share

Recommended Posts

I updated my version 2 posts up to fix the image disappearing when moving / minimizing the GUI.

Brilliant- works great! Thanks for your work, both of you.

...and now I'm REALLY happy because I've discovered how to create depth maps in Google Sketchup, so I've been able to make some impressive stereograms of some of the buildings my company has designed that I'd already modeled in 3-d.

Good stuff :P

"There are 10 types of people in this world - those who can read binary, and those who can't.""We've heard that a million monkeys at a million keyboards could produce the complete works of Shakespeare; now, thanks to the Internet, we know that is not true." ~Robert Wilensky0101101 1001010 1100001 1101101 1100101 1110011 0110011 1001101 10001110000101 0000111 0001000 0001110 0001101 0010010 1010110 0100001 1101110
Link to comment
Share on other sites

Brilliant- works great! Thanks for your work, both of you.

...and now I'm REALLY happy because I've discovered how to create depth maps in Google Sketchup, so I've been able to make some impressive stereograms of some of the buildings my company has designed that I'd already modeled in 3-d.

Good stuff :P

Please, do tell your technique for making depth maps. =D

[center][/center]Working on the next big thing.Currently Playing: Halo 4, League of LegendsXBL GT: iRememberYhslaw

Link to comment
Share on other sites

Please, do tell your technique for making depth maps. =D

I found the information on this page...scroll to the bottom and look for the video labeled "Google SketchUp and Photoshop: Lens Blur (8:53)"...it's the second picture he exports in this demo for use in Photoshop

The short version is this:

- Open up Google Sketchup (free, great program...I've used it since before it was bought by google and made free)

- Make/get a 3d model (it will import 3d models from AutoCAD, 3dStudio, etc, plus there's a whole library of models and an online library for downloading other models that people have done)

- Go to a hiddenline view (no colors, straight lines)

- Make sure that shadows are off

- Make your lines NEARLY white (all white will make everything go negative, apparently)

- Turn the ground and sky off and set the background color to white

- Now, turn on fog. Recolor the fog to black instead of the default white

- Adjust the fog density with the near and far sliders, so that the closest point to you is white and the farthest is nearly black

- Export the .jpg image

That's it! It works really quite well. :P

Posted Image

Edited by james3mg
"There are 10 types of people in this world - those who can read binary, and those who can't.""We've heard that a million monkeys at a million keyboards could produce the complete works of Shakespeare; now, thanks to the Internet, we know that is not true." ~Robert Wilensky0101101 1001010 1100001 1101101 1100101 1110011 0110011 1001101 10001110000101 0000111 0001000 0001110 0001101 0010010 1010110 0100001 1101110
Link to comment
Share on other sites

Update again (5 posts up). Now it uses direct calls to GDI to get pixel color, so we don't have to disable composition in Vista anymore.

Nice...

I've taken your script (latest as of this writing :( ) and modified it a bit more: now you choose what type of image output you want: black/white random dots, colored random dots, or a tiled wallpaper image that you provide (you have to do the tiling yourself ahead of time), then you can load the depthmap that you want to use (the grayscale image you've always provided for this script), and click go. Once it's rendered, you can change the output without having to re-provide the depth map, or you can give it a new depth map to render using the SAME output (literally the same pattern...good if you're making an animation, since the "static" in the background won't change from frame to frame).

So it's not really different from wraithdu's port of andybiochem's original (excellent) script, it's just got a few tweaks to give different types of output, and does the image reading when the image(s) is/are provided, so it renders the teensiest bit faster once you hit 'go'. I find the colored random dots to be the easiest to see, FWIW. Oh, and if you provide your own tiled wallpaper, I highly recommend that you tile it horizontally at 100 pixels and have it actually be an 800x500 image (edit:) the exact size of the output you want, (set by dragging resizable GUI) for best results. It doesn't have to tile vertically at all, but it sure can if you want it to.

enjoy!

Edit: fixed typo

Edit2: fixed poor programming habits...thanks wraithdu (see next post)

Edit3: now GUI is resizable to set the size of output you want! Tiled wallpaper should still tile at 100px horizontally, regardless of output size.

Edit4: save function added, thanks to wraithdu's leaving the necessary code commented in the source that I could copy :P

#include <GUIConstants.au3>
#include <GdiPlus.au3>
#include <WindowsConstants.au3>

Opt("GUIOnEventMode", 1)
Opt("PixelCoordMode", 2)

Global $graphic, $pWhite, $pBlack, $fdraw = False, $graphic1, $hBMP, $aNoisePattern, $aProfilePattern, $tooltipTimer
Global $xSize=800, $ySize=500

_GDIPlus_Startup()

;**************************************************************************************
;GUI
;**************************************************************************************
$GUI = GUICreate("Stereogram creator", $xSize + 19, $ySize + 100, -1, -1, BitOR($GUI_SS_DEFAULT_GUI,$WS_SIZEBOX))
GUISetOnEvent($GUI_EVENT_CLOSE,"close")

;**************************************************************************************
; User
;**************************************************************************************
;----- Graphic control -----

$Picture = GUICtrlCreatePic("",9,9,$xSize,$ySize)
GUICtrlSetResizing(-1,102)

;----- buttons/input -----
GUICtrlCreateLabel("Set a new finished pattern type:",10,$ySize + 15,150,18)
GUICtrlSetResizing(-1,64+768+2)
GUICtrlCreateButton("Black/White random",20,$ySize + 30,140,20)
GUICtrlSetOnEvent(-1,"_CreateBWNoise")
GUICtrlSetResizing(-1,64+768+2)
GUICtrlCreateButton("Colored random",20,$ySize + 50,140,20)
GUICtrlSetOnEvent(-1,"_CreateColorNoise")
GUICtrlSetResizing(-1,64+768+2)
GUICtrlCreateButton("Tiled wallpaper",20,$ySize + 70,140,20)
GUICtrlSetOnEvent(-1,"_LoadWallpaper")
GUICtrlSetResizing(-1,64+768+2)


$LoadPicButton=GUICtrlCreateButton("Load Depthmap",200,$ySize + 35,100,20)
GUICtrlSetOnEvent(-1,"_LoadDepthmap")
GUICtrlSetResizing(-1,64+768+2)
GUICtrlCreateLabel("Depth of field = ",200,$ySize + 65,75,18)
GUICtrlSetResizing(-1,64+768+2)
$TotalDepthInput = GUICtrlCreateInput(20,275,$ySize + 63,30,20)
GUICtrlSetResizing(-1,64+768+2)

$GoButton=GUICtrlCreateButton("GO", 340,$ySize + 45,100,25)
GUICtrlSetResizing(-1,64+768+2)
GUICtrlSetOnEvent(-1,"_Create_Stereogram")
GUICtrlSetFont(-1,15)
GUICtrlSetState(-1,$GUI_DISABLE)
$SaveButton=GUICtrlCreateButton("Save image", 340, $ySize+70,100,20)
GUICtrlSetResizing(-1,64+768+2)
GUICtrlSetOnEvent(-1,"SavePic")
GUICtrlSetState(-1,$GUI_DISABLE)

$TypeCheckBox = GUICtrlCreateCheckbox("Use converge method",340,$ySize + 20,200,20)
GUICtrlSetResizing(-1,64+768+2)

;----- progress-----
$Progress = GUICtrlCreateProgress(475,$ySize + 44,$xSize-475,25)
GUICtrlSetResizing(-1,64+4+512+2)

GUIRegisterMsg($WM_PAINT, "MY_WM_PAINT")
GUIRegisterMsg($WM_ERASEBKGND, "MY_WM_PAINT")
GUIRegisterMsg($WM_GETMINMAXINFO, "ResizeGUI")

GUISetState(@SW_SHOW)
;######################################################################################
; LOOP
;######################################################################################
While 1
    Sleep(100)
    If TimerDiff($tooltipTimer) > 750 Then
        $tooltipTimer=""
        ToolTip("")
    EndIf
WEnd
;######################################################################################
; END LOOP
;######################################################################################

Func ResizeGUI()
    Local $Csize=WinGetClientSize($GUI)
    $xSize=$Csize[0]-19
    $ySize=$Csize[1]-100
    If IsArray($aNoisePattern) AND IsArray($aProfilePattern) AND UBound($aNoisePattern)=$xSize+1 AND UBound($aProfilePattern)=$xSize+1 AND UBound($aNoisePattern,2) = $ySize+1 AND UBound($aProfilePattern,2) = $ySize+1 Then
        GUICtrlSetState($GoButton,$GUI_ENABLE)
    Else
        GUICtrlSetState($GoButton,$GUI_DISABLE)
    EndIf
    ToolTip($xSize&"x"&$ySize)
    $tooltipTimer=TimerInit()
EndFunc

Func Load_Pic()
;**************************************************************************************
; Load new picture
;**************************************************************************************
    $fdraw = False
    _GDIPlus_GraphicsDispose($graphic1)
    _GDIPlus_BitmapDispose($hBMP)
    ;----- renew pic -----
    $Image = FileOpenDialog("",".","Images (*.bmp;*.jpeg;*.jpg;*.gif)")
    If @error = 1 Then Return 0
    GUICtrlDelete($Picture)
    $Picture = GUICtrlCreatePic($Image,9,9,$xSize,$ySize)
    GUICtrlSetBkColor($graphic,0xFFFFFF)
    GUICtrlSetColor($graphic,0x000000)
    GUICtrlSetResizing(-1,102)
    Return 1
EndFunc

Func _CreateColorNoise()
    Global $aNoisePattern[$xSize+1][$ySize+1]
    For $x = 1 to 100
        For $y = 1 to $ySize
            $aNoisePattern[$x][$y] = "0x"&Hex(Random(0,16777215,1),6)
        Next
    Next
    $Copy=1
    While 1
        For $x = 1 to 100
            If $Copy*100+$x > $xSize Then ExitLoop 2
            For $y = 1 to $ySize
                $aNoisePattern[$x + ($Copy * 100)][$y] = $aNoisePattern[$x][$y]
            Next
        Next
        $Copy+=1
    WEnd
    If IsArray($aNoisePattern) AND IsArray($aProfilePattern) AND UBound($aNoisePattern)=$xSize+1 AND UBound($aProfilePattern)=$xSize+1 AND UBound($aNoisePattern,2) = $ySize+1 AND UBound($aProfilePattern,2) = $ySize+1 Then GUICtrlSetState($GoButton,$GUI_ENABLE)
    GUICtrlSetState($SaveButton,$GUI_DISABLE)
EndFunc

Func _CreateBWNoise()
    Global $aNoisePattern[$xSize+1][$ySize+1]
    For $x = 1 to 100
        For $y = 1 to $ySize
            $aNoisePattern[$x][$y] = "0x"&Hex(Random(0,1,1)*0xFFFFFF,6)
        Next
    Next
    $copy=1
    While 1
        For $x = 1 to 100
            If $Copy*100+$x > $xSize Then ExitLoop 2
            For $y = 1 to $ySize
                $aNoisePattern[$x + ($Copy * 100)][$y] = $aNoisePattern[$x][$y]
            Next
        Next
        $Copy+=1
    Wend
    If IsArray($aNoisePattern) AND IsArray($aProfilePattern) AND UBound($aNoisePattern)=$xSize+1 AND UBound($aProfilePattern)=$xSize+1 AND UBound($aNoisePattern,2) = $ySize+1 AND UBound($aProfilePattern,2) = $ySize+1 Then GUICtrlSetState($GoButton,$GUI_ENABLE)
    GUICtrlSetState($SaveButton,$GUI_DISABLE)
EndFunc

Func _LoadWallpaper()
    If Load_Pic() = 0 Then Return
    GUISetState(@SW_DISABLE)
    WinSetOnTop($GUI,"",1)
    
    ConsoleWrite("Getting pixel colors..." & @CRLF)
    $hGDI = DllOpen("gdi32.dll")
    $hDC = _WinAPI_GetDC($GUI)
    If @error Then ConsoleWrite("Error getting DC" & @CRLF)
    Global $aNoisePattern[$xSize+1][$ySize+1]
    For $x = 1 to $xSize
        For $y = 1 to $ySize
            $ret = DllCall($hGDI, "int", "GetPixel", "hwnd", $hDC, "int", $x + 9, "int", $y + 9)
;~    $aProfilePattern[$x][$y] = PixelGetColor($x + 9,$y + 9,$GUI)
            $aNoisePattern[$x][$y] = BGRtoRGB($ret[0])
        Next
        GUICtrlSetData($Progress,$x/($xSize/100))
    Next
    _WinAPI_ReleaseDC($GUI, $hDC)
    DllClose($hGDI)
    ConsoleWrite("Finished getting pixel data." & @CRLF)
    GUICtrlDelete($Picture)
    $Picture = GUICtrlCreatePic("",9,9,$xSize,$ySize)
    GUICtrlSetResizing(-1,102)
    GUICtrlSetData($Progress,0)
    If IsArray($aNoisePattern) AND IsArray($aProfilePattern) AND UBound($aNoisePattern)=$xSize+1 AND UBound($aProfilePattern)=$xSize+1 AND UBound($aNoisePattern,2) = $ySize+1 AND UBound($aProfilePattern,2) = $ySize+1 Then GUICtrlSetState($GoButton,$GUI_ENABLE)
    GUISetState(@SW_ENABLE)
    WinSetOnTop($GUI,"",0)
    GUICtrlSetState($SaveButton,$GUI_DISABLE)
EndFunc

Func _LoadDepthmap()
    If Load_Pic() = 0 Then Return
    GUISetState(@SW_DISABLE)
    WinSetOnTop($GUI,"",1)
    ; This creates a profile used to off-set the NoisePattern
    ConsoleWrite("Getting pixel colors..." & @CRLF)
    $hGDI = DllOpen("gdi32.dll")
    $hDC = _WinAPI_GetDC($GUI)
    If @error Then ConsoleWrite("Error getting DC" & @CRLF)
    Global $aProfilePattern[$xSize+1][$ySize+1]
    For $x = 1 to $xSize
        For $y = 1 to $ySize
            $ret = DllCall($hGDI, "int", "GetPixel", "hwnd", $hDC, "int", $x + 9, "int", $y + 9)
            $aProfilePattern[$x][$y] = BGRtoRGB($ret[0])
        Next
        GUICtrlSetData($Progress,$x/($xSize/100))
    Next
    _WinAPI_ReleaseDC($GUI, $hDC)
    DllClose($hGDI)
    ConsoleWrite("Finished getting pixel data." & @CRLF)
    GUICtrlSetData($Progress,0)
    If IsArray($aNoisePattern) AND IsArray($aProfilePattern) AND UBound($aNoisePattern)=$xSize+1 AND UBound($aProfilePattern)=$xSize+1 AND UBound($aNoisePattern,2) = $ySize+1 AND UBound($aProfilePattern,2) = $ySize+1 Then GUICtrlSetState($GoButton,$GUI_ENABLE)
    GUISetState(@SW_ENABLE)
    WinSetOnTop($GUI,"",0)
    GUICtrlSetState($SaveButton,$GUI_DISABLE)
EndFunc

Func _Create_Stereogram()
    If NOT (IsArray($aNoisePattern) AND IsArray($aProfilePattern) AND UBound($aNoisePattern)=$xSize+1 AND UBound($aProfilePattern)=$xSize+1 AND UBound($aNoisePattern,2) = $ySize+1 AND UBound($aProfilePattern,2) = $ySize+1) Then
        GUICtrlSetState($GoButton,$GUI_DISABLE)
        Return
    EndIf
    GUIRegisterMsg($WM_GETMINMAXINFO, "")
    ; Decide on depth for each pixel (scale 1 to $TotalDepth)
    $TotalDepth = GUICtrlRead($TotalDepthInput)
    For $x = 1 to $xSize
        For $y = 1 To $ySize
            $cCol = BitAND($aProfilePattern[$x][$y],255)
            $aProfilePattern[$x][$y] = (($TotalDepth/255) * $cCol)
            if GUICtrlRead($TypeCheckBox) = 1 Then $aProfilePattern[$x][$y] = $TotalDepth - $aProfilePattern[$x][$y]
        Next
        GUICtrlSetData($Progress,$x/($xSize/25))
    Next
    ;----- Apply depth as off-set -----
    $CriticalWidth = 100
    For $x = $TotalDepth to $xSize
        For $y = 1 to $ySize
            $Offset = ($x - $aProfilePattern[$x][$y])
            Do
            $aNoisePattern[$Offset][$y] = $aNoisePattern[$x][$y]
            $Offset += $CriticalWidth
            Until $Offset >= $xSize
        Next
        GUICtrlSetData($Progress,25+$x/($xSize/25))
    Next
    
    ;----- draw edited noise blocks -----
    GUICtrlDelete($Picture)
    $graphic1 = _GDIPlus_GraphicsCreateFromHWND($GUI)
    $hBMP = _GDIPlus_BitmapCreateFromGraphics($xSize, $ySize, $graphic1)
    $graphic2 = _GDIPlus_ImageGetGraphicsContext($hBMP)
    For $x = 1 to $xSize
        For $y = 1 to $ySize
            $pColor = _GDIPlus_PenCreate(BitOR($aNoisePattern[$x][$y],0xFF000000))
            _GDIPlus_GraphicsDrawRect($graphic2, $x, $y, 1, 1, $pColor)
            _GDIPlus_PenDispose($pColor)
        Next
        GUICtrlSetData($Progress,50+$x/($xSize/50))
    Next
    _GDIPlus_GraphicsDispose($graphic2)
    $fdraw = True
;~  _GDIPlus_ImageSaveToFile($hBMP, @DesktopDir & "\stereo1.jpg")
    _GDIPlus_GraphicsDrawImageRect($graphic1, $hBMP, 0, 0, $xSize, $ySize)

    GUICtrlSetData($Progress,0)
    GUIRegisterMsg($WM_GETMINMAXINFO, "ResizeGUI")
    GUICtrlSetState($SaveButton,$GUI_ENABLE)
EndFunc

Func SavePic()
    $SaveFile=FileSaveDialog("Save image as...","","jpg image (*.jpg)",18,"stereogram1.jpg")
    If NOT @error Then _GDIPlus_ImageSaveToFile($hBMP, $SaveFile)
EndFunc

Func MY_WM_PAINT($hwnd, $msg, $wparam, $lparam)
    If $fdraw Then _GDIPlus_GraphicsDrawImageRect($graphic1, $hBMP, 0, 0, $xSize, $ySize)
    Return $GUI_RUNDEFMSG
EndFunc

Func BGRtoRGB($iColor)
    Return Int(BitOR(BitShift(BitAND($iColor, 0xFF), -16), BitAND($iColor, 0xFF00), BitShift(BitAND($iColor, 0xFF0000), 16)))
EndFunc

Func close()
;**************************************************************************************
; Bye bye!!
;**************************************************************************************
    _GDIPlus_GraphicsDispose($graphic1)
    _GDIPlus_BitmapDispose($hBMP)
    _GDIPlus_Shutdown()
    Exit
EndFunc
Posted ImagePosted Image Edited by james3mg
"There are 10 types of people in this world - those who can read binary, and those who can't.""We've heard that a million monkeys at a million keyboards could produce the complete works of Shakespeare; now, thanks to the Internet, we know that is not true." ~Robert Wilensky0101101 1001010 1100001 1101101 1100101 1110011 0110011 1001101 10001110000101 0000111 0001000 0001110 0001101 0010010 1010110 0100001 1101110
Link to comment
Share on other sites

Nice! I've yet to try it, but I'm looking forward to it. The only change I would make is -

$pColor = _GDIPlus_PenCreate($aNoisePattern[$x][$y]+0xFF000000)

to

$pColor = _GDIPlus_PenCreate(BitOR($aNoisePattern[$x][$y], 0xFF000000))

BitOR'ing is technically the correct method for this operation.

Link to comment
Share on other sites

BitOR'ing is technically the correct method for this operation.

While you're correct, I've never really understood the difference...it gives the same result either way, and adding it is easier than bitor'ing it from a legability standpoint, imho. They're all just numbers, after all, so whether I "combine" them, bit style, or just add them together, I don't see how anything would ever break either way.

Of course, AutoIt, ASP, HTML and JS are as deep into "programming" as I go, and none of them are really "programming" at all. :P So there's probably some deep, dark reason that my feeble mind couldn't grasp.

"There are 10 types of people in this world - those who can read binary, and those who can't.""We've heard that a million monkeys at a million keyboards could produce the complete works of Shakespeare; now, thanks to the Internet, we know that is not true." ~Robert Wilensky0101101 1001010 1100001 1101101 1100101 1110011 0110011 1001101 10001110000101 0000111 0001000 0001110 0001101 0010010 1010110 0100001 1101110
Link to comment
Share on other sites

Well in this particular usage, yes the end result is the same. However consider this -

BitOR(0xFF, 0xFF) = 0xFF

0xFF + 0xFF = 0x01FE

The AutoIt helpfile gives a pretty good description of the Bit operators. No sense in me repeating it here.

Edited by wraithdu
Link to comment
Share on other sites

Well in this particular usage, yes the end result is the same. However consider this -

BitOR(0xFF, 0xFF) = 0xFF

0xFF + 0xFF = 0x01FE

The AutoIt helpfile gives a pretty good description of the Bit operators. No sense in me repeating it here.

I'm familiar with the BIT functions already, and you're right...no use repeating in the forum what's in the help file. But you're also right that I certainly hadn't considered cases where you're BitOR'ing numbers together which may occupy some of the same bits (even though that'd be MOST of the operations out there :P ). I'm just used to using this stuff with flags where the numbers you're combining are mutually-exclusive. Thanks :(

(oh, and I'd already taken your advice in the posted snippet, so it's correct now).

Edited by james3mg
"There are 10 types of people in this world - those who can read binary, and those who can't.""We've heard that a million monkeys at a million keyboards could produce the complete works of Shakespeare; now, thanks to the Internet, we know that is not true." ~Robert Wilensky0101101 1001010 1100001 1101101 1100101 1110011 0110011 1001101 10001110000101 0000111 0001000 0001110 0001101 0010010 1010110 0100001 1101110
Link to comment
Share on other sites

WOW!

I've always loved stereograms, they're so cool.

this is really cool

u had a great idea, weldone!!!

My own pocket emo http://www.mindistortion.net/pocketemo/?da...1-7-2-0-0-1-0-0LOL[quote name='beerman' post='399180' date='Sep 6 2007, 08:45 AM']I have learned, never think inside the box. The moment you have a bright idea, and stand up to quickly exclaiming, "Eureka, I have it!". You will knock yourself out, from bashing your head on the inside of the box as you stand... So in conclusion it is always safer to think outside the box. :)[/quote]

Link to comment
Share on other sites

I've updated my version of this script in the post 7 up (post 26)...now you can resize the GUI so you can have any size output you want! While resizing, you'll see a tooltip telling you exactly how large the output will be. Note that once you resize the GUI, you'll have to (re)create the noise pattern and (re)set the depth map, as the old data won't work at the new size. The GUI will remind you of that by disabling the Go! button again until you give it both parameters again. So: just resize first :P

If you want to do the tiled wallpaper style, you'll still want it to tile every 100 pixels (the 100 doesn't resize), and make sure that you set the GUI to give you an output that's the same size as the wallpaper image you provide so it doesn't stretch/shrink the wallpaper and goof up the 100 pixel measurment.

Edit: OK, I just updated it again to give you a save button :(

Edited by james3mg
"There are 10 types of people in this world - those who can read binary, and those who can't.""We've heard that a million monkeys at a million keyboards could produce the complete works of Shakespeare; now, thanks to the Internet, we know that is not true." ~Robert Wilensky0101101 1001010 1100001 1101101 1100101 1110011 0110011 1001101 10001110000101 0000111 0001000 0001110 0001101 0010010 1010110 0100001 1101110
Link to comment
Share on other sites

Once again this script makes me smile. I have a small itch however in the fact that you can't have a window over it while it's working. This bugs me. I'm sure there must be a cleaner way to do this. *itch scratched*

[center][/center]Working on the next big thing.Currently Playing: Halo 4, League of LegendsXBL GT: iRememberYhslaw

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...