Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Better support for the xinsir controlnet openpose (sdxl) #447

Closed
Satoshi-Yoda opened this issue Sep 3, 2024 · 3 comments
Closed

Better support for the xinsir controlnet openpose (sdxl) #447

Satoshi-Yoda opened this issue Sep 3, 2024 · 3 comments

Comments

@Satoshi-Yoda
Copy link

Satoshi-Yoda commented Sep 3, 2024

Good day! :3
At the moment this looks like the best controlnet for openpose:
https://huggingface.co/xinsir/controlnet-openpose-sdxl-1.0
And for some reason it was trained with non-default pose lines (and dots), they were made significantly thicker.
It still works good with default lines, but with thicker lines it works better.

The recommended solution is to modify the code that do the drawing of the poses.
Actual reference code could be found on that huggingface page in the model card.
But it is for openpose, not dw openpose (the difference is in normalized coords).
So, personally I made something like that in this file

/ComfyUI/custom_nodes/comfyui_controlnet_aux/src/controlnet_aux/dwpose/util.py

(only the thing about ratio was added)

def draw_bodypose(canvas: np.ndarray, keypoints: List[Keypoint]) -> np.ndarray:
    """
    Draw keypoints and limbs representing body pose on a given canvas.

    Args:
        canvas (np.ndarray): A 3D numpy array representing the canvas (image) on which to draw the body pose.
        keypoints (List[Keypoint]): A list of Keypoint objects representing the body keypoints to be drawn.

    Returns:
        np.ndarray: A 3D numpy array representing the modified canvas with the drawn body pose.

    Note:
        The function expects the x and y coordinates of the keypoints to be normalized between 0 and 1.
    """
    if not is_normalized(keypoints):
        H, W = 1.0, 1.0
    else:
        H, W, _ = canvas.shape


    CH, CW, _ = canvas.shape

    if max(CW, CH) < 500:
        ratio = 1.0
    elif max(CW, CH) >= 500 and max(CW, CH) < 1000:
        ratio = 2.0
    elif max(CW, CH) >= 1000 and max(CW, CH) < 2000:
        ratio = 3.0
    elif max(CW, CH) >= 2000 and max(CW, CH) < 3000:
        ratio = 4.0
    elif max(CW, CH) >= 3000 and max(CW, CH) < 4000:
        ratio = 5.0
    elif max(CW, CH) >= 4000 and max(CW, CH) < 5000:
        ratio = 6.0
    else:
        ratio = 7.0

    stickwidth = 4

    limbSeq = [
        [2, 3], [2, 6], [3, 4], [4, 5], 
        [6, 7], [7, 8], [2, 9], [9, 10], 
        [10, 11], [2, 12], [12, 13], [13, 14], 
        [2, 1], [1, 15], [15, 17], [1, 16], 
        [16, 18],
    ]

    colors = [[255, 0, 0], [255, 85, 0], [255, 170, 0], [255, 255, 0], [170, 255, 0], [85, 255, 0], [0, 255, 0], \
              [0, 255, 85], [0, 255, 170], [0, 255, 255], [0, 170, 255], [0, 85, 255], [0, 0, 255], [85, 0, 255], \
              [170, 0, 255], [255, 0, 255], [255, 0, 170], [255, 0, 85]]

    for (k1_index, k2_index), color in zip(limbSeq, colors):
        keypoint1 = keypoints[k1_index - 1]
        keypoint2 = keypoints[k2_index - 1]

        if keypoint1 is None or keypoint2 is None:
            continue

        Y = np.array([keypoint1.x, keypoint2.x]) * float(W)
        X = np.array([keypoint1.y, keypoint2.y]) * float(H)
        mX = np.mean(X)
        mY = np.mean(Y)
        length = ((X[0] - X[1]) ** 2 + (Y[0] - Y[1]) ** 2) ** 0.5
        angle = math.degrees(math.atan2(X[0] - X[1], Y[0] - Y[1]))
        polygon = cv2.ellipse2Poly((int(mY), int(mX)), (int(length / 2), int(stickwidth * ratio)), int(angle), 0, 360, 1)
        cv2.fillConvexPoly(canvas, polygon, [int(float(c) * 0.6) for c in color])

    for keypoint, color in zip(keypoints, colors):
        if keypoint is None:
            continue

        x, y = keypoint.x, keypoint.y
        x = int(x * W)
        y = int(y * H)
        cv2.circle(canvas, (int(x), int(y)), int(4 * ratio), color, thickness=-1)

    return canvas

Works like a charm!
And looks easy, but that would be "less than optimal", because such drastic change could potentially break other older workflows, so maybe it should be done with some checkbox (disabled by default) or some other way to only optionally enable it?

@Fannovel16
Copy link
Owner

Fannovel16 commented Sep 4, 2024

@Satoshi-Yoda Hmm interesting. I can add a new option "scale_line_for_xinsr"

@Fannovel16
Copy link
Owner

Fannovel16 commented Sep 4, 2024

The new option on DWPose and OpenPose is now called "scale_stick_for_xinsr_cn" and it's disabled by default

@Satoshi-Yoda
Copy link
Author

Amazing! Thank you =)
I also noticed a couple of possible things: b1094d7#commitcomment-146217878

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants