Grasshopper

algorithmic modeling for Rhino

I would like to change the referenced file in the image sampler through grasshopper or a scripting component, instead of entering the file path manually. Currently, the obvious way to change which image is used in the image sampler is to manually select a new file after double-clicking on the component. Would it be possible to externalize the input of the file path so that I could draw from a list of file paths, and so that I could change which image is used from within grasshopper?
Is there a way to edit the file path input with a VB component?

I am trying to reference specific image files from a list of images, using their index, and I want the image sampler to update accordingly. What is the best way of approaching this?

Thanks for any possible advice,

Ben

Views: 4553

Replies to This Discussion

I can't speak to whether that's possible or not (it might be, but it also might cause issues), but you can just load the image yourself. You'd have to sample the image yourself, which means that you'd have to translate parameters into the pixels (which shouldn't be hard). This won't necessarily be as efficient as the image sampler component, but since you're change the image anyway, it shouldn't be that much of an issue. See the attached for retrieving a pixel from a bitmap...
Attachments:
Thanks Damien! It works great!
I've edited it to process a list of points.

Attachments:
Does anyone happen to know where I could find out the range of image file formats that the GetPixel method works with?
http://msdn.microsoft.com/en-us/library/system.drawing.bitmap.aspx

"GDI+ supports the following file formats: BMP, GIF, EXIG, JPG, PNG and TIFF. For more information about supported formats, see Types of Bitmaps."
thanks!
I've come to believe that Marshall.ReadByte works a lot faster than GetPixel, though the code is a bit more complex. See this discussion for reference. However, if you are changing the image every so often, the difference might not be significant.

I tried another method, where I opened the image, performed getPixel for every pixel on the image, stored the values in separate R-G-B arrays, and only used these arrays to read values later, which worked out be the fastest method around. Here's a comparison:


Just thought it might help you optimize code for speed because I've found image reading to be annoyingly slow at times.
GetPixel and SetPixel are the slowest possible calls. What I do in the Image sampler is to copy the entire bitmap data into a ByteArray, then directly access the elements. It's even faster than Marshal.ReadByte, provided you sample it a lot. There is of course plenty of overhead in copying the image data.

If you wrote the script in C#, you could use the unsafe keyword to get the best of both worlds.

--
David Rutten
david@mcneel.com
Poprad, Slovakia
As a subset of this discussion, I would also like to ask how could one use
Grasshopper.Kernel.GH_FileWatcher.FileChanged?

For cases when we use a custom script to read images (like in my case, I need the image read in a recursive loop), it would be good to have the dynamic update functionality that the native GH image sampler offers.

I figured that Grasshopper.Kernel.GH_FileWatcher.FileChanged does create some kind of an event, which requires an AddressOf handler, but somehow doesn't let me use it either which way I try...
When you construct this class, you must supply the filepath as well as a delegate that will be called when the file in question actually changes.

So somewhere there should be a method that matches the GH_FileWatcher.FileChanged delegate.

Then, when you construct your GH_FileWatcher, use AddressOf to supply this method:

...
m_watcher = New GH_FileWatcher(myFilePath, true, AddressOf FileChanged)
...

Private Sub FileChanged(ByVal sender As GH_FileWatcher, _
ByVal file_path As String, _
ByVal type As WatcherChangeTypes)
' Do whatever it is you need to do when the file changes.
' You should eventually call ExpireSolution(True) on the
' owner component of the script to force an update.
End Sub

--------------------

If you can't figure it out, GH_FileWatcher is nothing more than a thin wrapper class around System.IO.FileSystemWatcher. Most notably, GH_FileWatcher makes sure that the event is handled inside the UI thread of Grasshopper.

--
David Rutten
david@mcneel.com
Poprad, Slovakia
Got it! Thanks!

I was confused with the fact that a GH_Watcher needed a FileChanged delegate in its constructor, and a FileChanged delegate needed a GH_Watcher in its constructor.. so it was like the chicken and egg story for me.

But when you use it above, it clears a lot of conceptual VB stuff in my head. Thanks again!

Hey David,

 

Any chance you or someone else could post the above component? The one where you state

 

"GetPixel and SetPixel are the slowest possible calls. What I do in the Image sampler is to copy the entire bitmap data into a ByteArray, then directly access the elements. It's even faster than Marshal.ReadByte, provided you sample it a lot. There is of course plenty of overhead in copying the image data.

If you wrote the script in C#, you could use the unsafe keyword to get the best of both worlds."

 

I need a component like the get pixel that I specify the file type that works faster then the get pixel method.I would be extremely helped out of a tough spot for a workshop I've been preparing. Thank you so much.

 

Best,

Rob

Hi Rob,

 

if you're to do this within Grasshopper, just use the Grasshopper.Kernel.GH_MemoryBitmap class. It has the ultra fast sampling build in, as well as a bunch of pixel effects I need left and right.

 

When you create a new instance of the GH_MemoryBitmap class, it will lock the bitmap bytes into memory, meaning the image becomes just so much ones-and-zeros. Then when you're done sampling/changing the bitmap, you need to call the Release() method to make sure the bits become unlocked again and the bitmap can once again be used by other functions. If you don't call Release, the bitmap (in memory) will forever remain locked and inaccessible.

 

Something akin to this would be ideal:

 

'Declare a new sampler class

Dim sampler As New GH_MemoryBitmap(myBitmap)

Try

  'Iterate over all sampling locations

  For Each point in allSamplePoints

    Dim col As Color = Color.Transparent

    'Sample the bitmap at {x,y}

    If (sampler.Sample(point.X, point.Y, col)) Then

      'If the sampling op went fine, append the colour to a list

      sampleResult.Add(col)

    End If    

  Next

Catch ex As Exception

  'Report on any errors

Finally

  'Always, always, always Release the memory bitmap.

  If (sampler IsNot Nothing) Then sampler.Release()

End Try

 

--

David Rutten

david@mcneel.com

Poprad, Slovakia

RSS

About

Translate

Search

© 2024   Created by Scott Davidson.   Powered by

Badges  |  Report an Issue  |  Terms of Service