Create CPython components using Hops in Grasshopper

That is correct. I’m hoping to ship a new version of ghhops-server library very soon with list support.

3 Likes

ghhops-server 1.2.0 now on available on pypi

You should be able to have lists as inputs and outputs now. Here’s a modified version of the pointat sample that

  • takes a curve and a list of numbers as input
  • returns a list of points
@hops.component(
    "/pointsat",
    name="PointsAt",
    nickname="PtsAt",
    description="Get points along curve",
    icon="examples/pointat.png",
    inputs=[
        hs.HopsCurve("Curve", "C", "Curve to evaluate"),
        hs.HopsNumber("t", "t", "Parameters on Curve to evaluate", hs.HopsParamAccess.LIST),
    ],
    outputs=[
        hs.HopsPoint("P", "P", "Points on curve at t")
    ]
)
def pointsat(curve, t):
    points = [curve.PointAt(item) for item in t]
    return points
5 Likes

@stevebaer, it appears to be working correctly without having to state the HopsParamAccess:

https://hops-online.herokuapp.com/plevels

ITEM and LIST access are only really used for defining inputs. By default, the input is defined as Item and you python function will get a single item for the input parameter. When set to LIST, the input parameter will be a list.

True; I was forgetting about that.

Also works pretty well for interop with other programs :wink:
Here’s BlenderHops:

19 Likes

That’s awesome, @tom_svilans!

Does it connect automatically to a running session in Blender and extract all meshes?

You boot the script in Blender and attach to the Flask app as in the example script, but running it from Blender gives you access to bpy and all the Blender data. It’s not more than that, and it freezes the Blender UI because the Flask app ties up the script execution, which could probably be developed into something that runs in the background somehow.

But, as an example of using Hops it with whatever Python environment you have available, it does seem to be very powerful…

2 Likes

Here is a webinar to learn how to use Hops, CPython and Machine learning together. This would apply to any external libraries, applications or services that have a Python API.

6 Likes

Lealand Curtis does a great job here explaining the necessity of Grasshopper, Cpython and Hops in more advanced Machine Learning tools. And he gets into some of the code he used to connect them all together:

8 Likes

Hi,
I’m getting a weird error in the Hops component in Grasshopper. I’ve defined a function in Python that returns a mesh, exactly as my previous Blender example.
However, now it refuses to connect with Grasshopper, and gives this error:
1. Solution exception:Unexpected character encountered while parsing value: U. Path '', line 0, position 0.

The path is http://localhost:5000/getmesh and I’ve also tried with http://127.0.0.1:5000/getmesh.

Any ideas about what might be causing it to fail? Also, is there a manual way to clear the caches? It often gives me an error message about code that has been changed (when it worked before), making me think that there was still a Flask app or something working in the background…

Face Emotion Recognizer test

from flask import Flask
import ghhops_server as hs
from fer import FER
import cv2
import rhino3dm

# register hops app as middleware
app = Flask(__name__)
hops = hs.Hops(app)

@hops.component(
    "/emotion",
    name="emotion",
    description="detect face emotion",
    icon="",
    inputs=[
        hs.HopsString("Image", "I", "Image file"),
        hs.HopsNumber("Index", "i", "Face index")
    ],
    outputs=[
        hs.HopsCurve("Curve", "C", "rectangle"),
        hs.HopsString("Top Emotion", "T", "Top Emotion"),
        hs.HopsString("Emotions", "E", "Emotions result")
    ]
)
def emotion(image,index):
    img = cv2.imread(image)
    detector = FER(mtcnn=True)
    result = detector.detect_emotions(img)
    top = []
    for i in range(len(result)):
        top_emotions = [max(e["emotions"], key=lambda key: e["emotions"][key]) for e in result]
        top_emotion = top_emotions[i]
        score = result[i]["emotions"][top_emotion]
        top.append([top_emotion, score])
    print(top)
    emotions_list = []
    rectangles = []
    for idx, name in enumerate(result):
        emotions = name["emotions"]
        bbox = name["box"]
        p1 = rhino3dm.Point3d(bbox[0], -bbox[1], 0)
        p2 = rhino3dm.Point3d(bbox[0], -bbox[1] - bbox[3], 0)
        p3 = rhino3dm.Point3d(bbox[0] + bbox[2], -bbox[1] - bbox[3], 0)
        p4 = rhino3dm.Point3d(bbox[0] + bbox[2], -bbox[1], 0)
        pts = [p1, p2, p3, p4, p1]
        poly = rhino3dm.Polyline(pts).ToPolylineCurve()
        rectangles.append(poly)
        emotions_list.append(emotions)

    print (rectangles)
    return rectangles[int(index)], top[int(index)], emotions_list

if __name__ == "__main__":
    app.run()
14 Likes

Haha, great example! :slight_smile:

2 Likes

Oh, you managed to create multiple outputs out of the Hops with CPython! I had a problems with that for some reason :slight_smile:

Cool example!

1 Like

With face contour, using faces in video also possible but i think it is very slow with Python and Grasshopper

from flask import Flask
import ghhops_server as hs
from fer import FER
import cv2
import rhino3dm
import dlib

# register hops app as middleware
app = Flask(__name__)
hops = hs.Hops(app)

@hops.component(
    "/emotion",
    name="emotion",
    description="detect face emotion",
    icon="",
    inputs=[
        hs.HopsString("Image", "I", "Image file"),
        hs.HopsNumber("Index", "i", "Face index")
    ],
    outputs=[
        hs.HopsCurve("Curve", "C", "rectangle"),
        hs.HopsString("Top Emotion", "T", "Top Emotion"),
        hs.HopsString("Emotions", "E", "Emotions result")
    ]
)

def emotion(image,index):
    img = cv2.imread(image)
    detector = FER(mtcnn=True)
    result = detector.detect_emotions(img)
    top = []
    for i in range(len(result)):
        top_emotions = [max(e["emotions"], key=lambda key: e["emotions"][key]) for e in result]
        top_emotion = top_emotions[i]
        score = result[i]["emotions"][top_emotion]
        top.append([top_emotion, score])

    emotions_list = []
    rectangles = []
    for idx, name in enumerate(result):
        emotions = name["emotions"]
        bbox = name["box"]
        p1 = rhino3dm.Point3d(bbox[0], -bbox[1], 0)
        p2 = rhino3dm.Point3d(bbox[0], -bbox[1] - bbox[3], 0)
        p3 = rhino3dm.Point3d(bbox[0] + bbox[2], -bbox[1] - bbox[3], 0)
        p4 = rhino3dm.Point3d(bbox[0] + bbox[2], -bbox[1], 0)
        pts = [p1, p2, p3, p4, p1]
        poly = rhino3dm.Polyline(pts).ToPolylineCurve()
        rectangles.append(poly)
        emotions_list.append(emotions)

    return rectangles[int(index)], top[int(index)], emotions_list

@hops.component(
    "/face",
    name="face",
    description="detect face",
    icon="",
    inputs=[
        hs.HopsString("Image", "I", "Image file")
    ],
    outputs=[
        hs.HopsPoint("Points", "P", "List of points")
    ]
)
def face(image):
    img = cv2.imread(image)
    detector = dlib.get_frontal_face_detector()
    predictor = dlib.shape_predictor("Your own folder//shape_predictor_68_face_landmarks.dat")
    gray = cv2.cvtColor(src=img, code=cv2.COLOR_BGR2GRAY)
    faces = detector(gray)
    points = []
    for face in faces:
        landmarks = predictor(image=gray, box=face)
        for n in range(0, 68):
            x = landmarks.part(n).x
            y = landmarks.part(n).y
            pt = rhino3dm.Point3d(x,-y,0)
            points.append(pt)
    return points

if __name__ == "__main__":
    app.run()

shape_predictor_68_face_landmarks

1 Like

If you try to hit that URL in your browser, do you get any results? That is a good way to check to see if things are working.

You can turn caching off on individual components with the right click context menu. You can also clear the entire cache by going to Grasshopper preferences and clicking on the clear cache button

Where can this button be found in the mac preferences?

Make sure you are using the latest version of Hops available on the package manager. This button was added in a recent release.

Oh, and based on your recent post; make sure to look at the grasshopper preferences and not rhino preferences. This is available in the menu when grasshopper is active on mac

Yep, I think I’ve unearthed another bug.

1 Like

When close Rhino and open it again hops component don’t work, just when cut and paste it.
How we can cut and paste a component with pyhton?