Create CPython components using Hops in Grasshopper

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?

Thanks @stevebaer ! I’ll give that a crack and will check the URL in the browser. Seems to be an issue if I boot the ghhops_server script from an IDE (Sublime Text in this case) - maybe multiple instances staying alive after killing the script - so I got around it by booting it from the console to be sure it gets destroyed when I kill it.

Hello @stevebaer
If this adress always used by hops http://127.0.0.1:5000/ or http://localhost:5000/ , can you make this possible by writing just the name of the component in the path case like this?

image

That form will probably get more advanced in the future. The address isn’t always localhost:5000, but we can check to see if this port is active and provide some sort of auto-complete list for available functions. The plan is for ghhops-server to provide a list of available functions that hops could read to help make this UI work.

1 Like

Thanks, what if the user can set the address than just write the name of the component?

image

I also try to use category and subcategory but looks don’t work

We could also provide autocomplete while typing in an address.

Category and subcategory are currently not used by Hops. We added these to the ghhops-server code in case we can get to the point where we could populate the grasshopper toolbar with components defined by ghhops-server. That’s still quite a ways off though.

4 Likes

Was this post meant for a new thread? I don’t understand what this has to do with Hops

Sounds very similar to this request

1 Like

Could you call the hops component through node in code scripting with Rhino.python: http://developer.rhino3d.com/guides/rhinopython/ghpython-call-components/

Thanks, we’ve seen this form of spam a bit lately.

hey @scottd! how do you pass the URL to hops with node-in-code? could you please provide an example?

1 Like

This is not currently available in node-in-code. See a discussion on the topic at

1 Like

I disagree : this is clearly a huge groundswell of popular support for my request :wink:

1 Like

Hi @stevebaer
I try a python code with the new update , when the output is a tree i got an error.

I don’t believe this is new with the latest release. The ghhops-server does not have support for outputting trees yet. If you need this functionality today, you might want to consider outputting json from python that represents your tree and using a tool like jswan to work with the json in grasshopper.

2 Likes