def keypoint_random_rotate(image, annos, mask=None, rg=<NUM_LIT>):
def _rotate_coord(shape, newxy, point, angle):<EOL><INDENT>angle = -<NUM_LIT:1> * angle / <NUM_LIT> * math.pi<EOL>ox, oy = shape<EOL>px, py = point<EOL>ox /= <NUM_LIT:2><EOL>oy /= <NUM_LIT:2><EOL>qx = math.cos(angle) * (px - ox) - math.sin(angle) * (py - oy)<EOL>qy = math.sin(angle) * (px - ox) + math.cos(angle) * (py - oy)<EOL>new_x, new_y = newxy<EOL>qx += ox - new_x<EOL>qy += oy - new_y<EOL>return int(qx + <NUM_LIT:0.5>), int(qy + <NUM_LIT:0.5>)<EOL><DEDENT>def _largest_rotated_rect(w, h, angle):<EOL><INDENT>"""<STR_LIT>"""<EOL>angle = angle / <NUM_LIT> * math.pi<EOL>if w <= <NUM_LIT:0> or h <= <NUM_LIT:0>:<EOL><INDENT>return <NUM_LIT:0>, <NUM_LIT:0><EOL><DEDENT>width_is_longer = w >= h<EOL>side_long, side_short = (w, h) if width_is_longer else (h, w)<EOL>sin_a, cos_a = abs(math.sin(angle)), abs(math.cos(angle))<EOL>if side_short <= <NUM_LIT> * sin_a * cos_a * side_long:<EOL><INDENT>x = <NUM_LIT:0.5> * side_short<EOL>wr, hr = (x / sin_a, x / cos_a) if width_is_longer else (x / cos_a, x / sin_a)<EOL><DEDENT>else:<EOL><INDENT>cos_2a = cos_a * cos_a - sin_a * sin_a<EOL>wr, hr = (w * cos_a - h * sin_a) / cos_2a, (h * cos_a - w * sin_a) / cos_2a<EOL><DEDENT>return int(np.round(wr)), int(np.round(hr))<EOL><DEDENT>img_shape = np.shape(image)<EOL>height = img_shape[<NUM_LIT:0>]<EOL>width = img_shape[<NUM_LIT:1>]<EOL>deg = np.random.uniform(-rg, rg)<EOL>img = image<EOL>center = (img.shape[<NUM_LIT:1>] * <NUM_LIT:0.5>, img.shape[<NUM_LIT:0>] * <NUM_LIT:0.5>)  <EOL>rot_m = cv2.getRotationMatrix2D((int(center[<NUM_LIT:0>]), int(center[<NUM_LIT:1>])), deg, <NUM_LIT:1>)<EOL>ret = cv2.warpAffine(img, rot_m, img.shape[<NUM_LIT:1>::-<NUM_LIT:1>], flags=cv2.INTER_AREA, borderMode=cv2.BORDER_CONSTANT)<EOL>if img.ndim == <NUM_LIT:3> and ret.ndim == <NUM_LIT:2>:<EOL><INDENT>ret = ret[:, :, np.newaxis]<EOL><DEDENT>neww, newh = _largest_rotated_rect(ret.shape[<NUM_LIT:1>], ret.shape[<NUM_LIT:0>], deg)<EOL>neww = min(neww, ret.shape[<NUM_LIT:1>])<EOL>newh = min(newh, ret.shape[<NUM_LIT:0>])<EOL>newx = int(center[<NUM_LIT:0>] - neww * <NUM_LIT:0.5>)<EOL>newy = int(center[<NUM_LIT:1>] - newh * <NUM_LIT:0.5>)<EOL>img = ret[newy:newy + newh, newx:newx + neww]<EOL>adjust_joint_list = []<EOL>for joint in annos:  <EOL><INDENT>adjust_joint = []<EOL>for point in joint:<EOL><INDENT>if point[<NUM_LIT:0>] < -<NUM_LIT:100> or point[<NUM_LIT:1>] < -<NUM_LIT:100>:<EOL><INDENT>adjust_joint.append((-<NUM_LIT:1000>, -<NUM_LIT:1000>))<EOL>continue<EOL><DEDENT>x, y = _rotate_coord((width, height), (newx, newy), point, deg)<EOL>if x > neww - <NUM_LIT:1> or y > newh - <NUM_LIT:1>:<EOL><INDENT>adjust_joint.append((-<NUM_LIT:1000>, -<NUM_LIT:1000>))<EOL>continue<EOL><DEDENT>if x < <NUM_LIT:0> or y < <NUM_LIT:0>:<EOL><INDENT>adjust_joint.append((-<NUM_LIT:1000>, -<NUM_LIT:1000>))<EOL>continue<EOL><DEDENT>adjust_joint.append((x, y))<EOL><DEDENT>adjust_joint_list.append(adjust_joint)<EOL><DEDENT>joint_list = adjust_joint_list<EOL>if mask is not None:<EOL><INDENT>msk = mask<EOL>center = (msk.shape[<NUM_LIT:1>] * <NUM_LIT:0.5>, msk.shape[<NUM_LIT:0>] * <NUM_LIT:0.5>)  <EOL>rot_m = cv2.getRotationMatrix2D((int(center[<NUM_LIT:0>]), int(center[<NUM_LIT:1>])), deg, <NUM_LIT:1>)<EOL>ret = cv2.warpAffine(msk, rot_m, msk.shape[<NUM_LIT:1>::-<NUM_LIT:1>], flags=cv2.INTER_AREA, borderMode=cv2.BORDER_CONSTANT)<EOL>if msk.ndim == <NUM_LIT:3> and msk.ndim == <NUM_LIT:2>:<EOL><INDENT>ret = ret[:, :, np.newaxis]<EOL><DEDENT>neww, newh = _largest_rotated_rect(ret.shape[<NUM_LIT:1>], ret.shape[<NUM_LIT:0>], deg)<EOL>neww = min(neww, ret.shape[<NUM_LIT:1>])<EOL>newh = min(newh, ret.shape[<NUM_LIT:0>])<EOL>newx = int(center[<NUM_LIT:0>] - neww * <NUM_LIT:0.5>)<EOL>newy = int(center[<NUM_LIT:1>] - newh * <NUM_LIT:0.5>)<EOL>msk = ret[newy:newy + newh, newx:newx + neww]<EOL>return img, joint_list, msk<EOL><DEDENT>else:<EOL><INDENT>return img, joint_list, None<EOL><DEDENT>
Rotate an image and corresponding keypoints.

    Parameters
    -----------
    image : 3 channel image
        The given image for augmentation.
    annos : list of list of floats
        The keypoints annotation of people.
    mask : single channel image or None
        The mask if available.
    rg : int or float
        Degree to rotate, usually 0 ~ 180.

    Returns
    ----------
    preprocessed image, annos, mask