kritsadaK commited on
Commit
01812af
·
1 Parent(s): 6011c2d

new version by using mediapipe

Browse files
Files changed (2) hide show
  1. app.py +93 -66
  2. graph_opt.pb +0 -3
app.py CHANGED
@@ -1,117 +1,141 @@
1
  import streamlit as st
2
  import cv2 as cv
3
  import numpy as np
 
4
  import tempfile
5
 
6
- # Paths to your files
7
- model_path = "graph_opt.pb"
 
8
 
9
- # Load the TensorFlow model
10
- net = cv.dnn.readNetFromTensorflow(model_path)
11
- if net.empty():
12
- raise FileNotFoundError(f"Model file not found or cannot be loaded: {model_path}")
 
 
 
13
 
14
- BODY_PARTS = {"Nose": 0, "Neck": 1, "RShoulder": 2, "RElbow": 3, "RWrist": 4,
15
- "LShoulder": 5, "LElbow": 6, "LWrist": 7, "RHip": 8, "RKnee": 9,
16
- "RAnkle": 10, "LHip": 11, "LKnee": 12, "LAnkle": 13, "REye": 14,
17
- "LEye": 15, "REar": 16, "LEar": 17, "Background": 18}
18
-
19
- # Adjust POSE_PAIRS to include only wrist to elbow parts
20
- POSE_PAIRS = [["RElbow", "RWrist"], ["LElbow", "LWrist"]]
21
 
22
- width = 368
23
- height = 368
24
- inWidth = width
25
- inHeight = height
26
- thr = 0.2
27
 
28
- def overlay_image_alpha(img, img_overlay, pos, alpha_mask):
29
- x, y = pos
 
30
 
31
- y1, y2 = max(0, y), min(img.shape[0], y + img_overlay.shape[0])
32
- x1, x2 = max(0, x), min(img.shape[1], x + img_overlay.shape[1])
 
33
 
34
- y1o, y2o = max(0, -y), min(img_overlay.shape[0], img.shape[0] - y)
35
- x1o, x2o = max(0, -x), min(img_overlay.shape[1], img.shape[1] - x)
 
36
 
 
37
  if y1 >= y2 or x1 >= x2 or y1o >= y2o or x1o >= x2o:
38
  return
39
 
 
40
  img_crop = img[y1:y2, x1:x2]
41
- img_overlay_crop = img_overlay[y1o:y2o, x1o:x2o]
42
- alpha = alpha_mask[y1o:y2o, x1o:x2o, np.newaxis]
43
  alpha_inv = 1.0 - alpha
44
 
45
  img_crop[:] = alpha * img_overlay_crop + alpha_inv * img_crop
46
 
47
- def poseDetector(frame, overlay_img):
48
- frameWidth = frame.shape[1]
49
- frameHeight = frame.shape[0]
50
-
51
- net.setInput(cv.dnn.blobFromImage(frame, 1.0, (inWidth, inHeight), (127.5, 127.5, 127.5), swapRB=True, crop=False))
52
- out = net.forward()
53
- out = out[:, :19, :, :]
54
 
55
- assert (len(BODY_PARTS) == out.shape[1])
56
-
57
- points = []
58
- for i in range(len(BODY_PARTS)):
59
- heatMap = out[0, i, :, :]
60
 
61
- _, conf, _, point = cv.minMaxLoc(heatMap)
62
- x = (frameWidth * point[0]) / out.shape[3]
63
- y = (frameHeight * point[1]) / out.shape[2]
64
 
65
- points.append((int(x), int(y)) if conf > thr else None)
 
 
 
 
 
66
 
67
- for pair in POSE_PAIRS:
68
- partFrom = pair[0]
69
- partTo = pair[1]
 
 
 
70
 
71
- assert (partFrom in BODY_PARTS)
72
- assert (partTo in BODY_PARTS)
 
73
 
74
- idFrom = BODY_PARTS[partFrom]
75
- idTo = BODY_PARTS[partTo]
 
76
 
77
- if points[idFrom] and points[idTo]:
78
- angle = np.degrees(np.arctan2(points[idTo][1] - points[idFrom][1], points[idTo][0] - points[idFrom][0]))
79
- adjusted_angle = angle + 270
 
80
 
81
- length = int(np.sqrt((points[idTo][0] - points[idFrom][0])**2 + (points[idTo][1] - points[idFrom][1])**2))
82
- reduced_length = int(length * 0.5)
83
 
84
- if reduced_length > 0 and overlay_img.shape[0] * 0.5 > 0:
85
- overlay_resized = cv.resize(overlay_img, (reduced_length, int(overlay_img.shape[0] * 0.5)))
 
86
 
87
- M = cv.getRotationMatrix2D((overlay_resized.shape[1] / 2, overlay_resized.shape[0] / 2), adjusted_angle, 1)
88
- overlay_rotated = cv.warpAffine(overlay_resized, M, (overlay_resized.shape[1], overlay_resized.shape[0]), flags=cv.INTER_LINEAR, borderMode=cv.BORDER_CONSTANT, borderValue=(0, 0, 0, 0))
 
89
 
90
- wrist_position = points[idTo]
91
- position = (int(wrist_position[0] - overlay_rotated.shape[1] / 2), int(wrist_position[1] - overlay_rotated.shape[0] / 2))
92
 
93
- alpha_mask = overlay_rotated[:, :, 3] / 255.0
94
- overlay_image_alpha(frame, overlay_rotated[:, :, :3], position, alpha_mask)
 
95
 
96
- t, _ = net.getPerfProfile()
97
  return frame
98
 
 
99
  def main():
100
- st.title("Video File Pose Detection and Tattoo Overlay")
101
 
 
102
  st.sidebar.header("Upload Tattoo Image and Video")
103
- uploaded_tattoo_img = st.sidebar.file_uploader("Upload Tattoo Image", type=["png"])
104
  uploaded_video = st.sidebar.file_uploader("Upload Video File", type=["mp4", "mov", "avi"])
105
 
106
  if uploaded_tattoo_img and uploaded_video:
107
- tattoo_img = cv.imdecode(np.frombuffer(uploaded_tattoo_img.read(), np.uint8), cv.IMREAD_UNCHANGED)
 
 
108
 
 
 
 
 
 
109
  run = st.checkbox('Run')
110
 
111
  if run:
 
112
  tfile = tempfile.NamedTemporaryFile(delete=False)
113
  tfile.write(uploaded_video.read())
114
 
 
115
  cap = cv.VideoCapture(tfile.name)
116
 
117
  stframe = st.empty()
@@ -121,7 +145,10 @@ def main():
121
  if not ret:
122
  break
123
 
 
124
  frame = poseDetector(frame, tattoo_img)
 
 
125
  frame = cv.cvtColor(frame, cv.COLOR_BGR2RGB)
126
  stframe.image(frame, channels="RGB")
127
 
 
1
  import streamlit as st
2
  import cv2 as cv
3
  import numpy as np
4
+ import mediapipe as mp
5
  import tempfile
6
 
7
+ # Initialize MediaPipe Pose
8
+ mp_pose = mp.solutions.pose
9
+ pose = mp_pose.Pose()
10
 
11
+ # Function to rotate an image around its center
12
+ def rotate_image(image, angle):
13
+ h, w = image.shape[:2]
14
+ center = (w // 2, h // 2)
15
+ rot_matrix = cv.getRotationMatrix2D(center, angle, 1.0)
16
+ rotated_image = cv.warpAffine(image, rot_matrix, (w, h), flags=cv.INTER_LINEAR)
17
+ return rotated_image
18
 
19
+ # Function to overlay the image with rotation following arm direction
20
+ def overlay_image_alpha_rotated(img, img_overlay, pos, alpha_mask, angle):
21
+ x, y = pos
 
 
 
 
22
 
23
+ # Rotate the overlay image in the opposite direction
24
+ img_overlay_rotated = rotate_image(img_overlay, -angle) # Negate the angle
25
+ alpha_mask_rotated = rotate_image(alpha_mask, -angle) # Negate the angle
 
 
26
 
27
+ # Calculate the new position after rotation
28
+ h, w = img_overlay_rotated.shape[:2]
29
+ new_pos = (x - w // 2, y - h // 2)
30
 
31
+ # Image ranges
32
+ y1, y2 = max(0, new_pos[1]), min(img.shape[0], new_pos[1] + h)
33
+ x1, x2 = max(0, new_pos[0]), min(img.shape[1], new_pos[0] + w)
34
 
35
+ # Overlay ranges
36
+ y1o, y2o = max(0, -new_pos[1]), min(h, img.shape[0] - new_pos[1])
37
+ x1o, x2o = max(0, -new_pos[0]), min(w, img.shape[1] - new_pos[0])
38
 
39
+ # Exit if nothing to overlay
40
  if y1 >= y2 or x1 >= x2 or y1o >= y2o or x1o >= x2o:
41
  return
42
 
43
+ # Blend overlay within the determined ranges
44
  img_crop = img[y1:y2, x1:x2]
45
+ img_overlay_crop = img_overlay_rotated[y1o:y2o, x1o:x2o]
46
+ alpha = alpha_mask_rotated[y1o:y2o, x1o:x2o, np.newaxis]
47
  alpha_inv = 1.0 - alpha
48
 
49
  img_crop[:] = alpha * img_overlay_crop + alpha_inv * img_crop
50
 
51
+ # Function to handle JPG images without alpha channel
52
+ def add_alpha_channel(image):
53
+ b_channel, g_channel, r_channel = cv.split(image)
54
+ alpha_channel = np.ones(b_channel.shape, dtype=b_channel.dtype) * 255 # Creating a fully opaque alpha channel
55
+ return cv.merge((b_channel, g_channel, r_channel, alpha_channel))
 
 
56
 
57
+ # Function to detect pose and overlay image following arm direction
58
+ def poseDetector(frame, overlay_img):
59
+ # Convert the image to RGB as MediaPipe expects RGB images
60
+ frame_rgb = cv.cvtColor(frame, cv.COLOR_BGR2RGB)
 
61
 
62
+ # Process the image and get the pose landmarks
63
+ results = pose.process(frame_rgb)
 
64
 
65
+ if results.pose_landmarks:
66
+ # Extract relevant landmarks
67
+ right_wrist = results.pose_landmarks.landmark[mp_pose.PoseLandmark.RIGHT_WRIST]
68
+ left_wrist = results.pose_landmarks.landmark[mp_pose.PoseLandmark.LEFT_WRIST]
69
+ right_elbow = results.pose_landmarks.landmark[mp_pose.PoseLandmark.RIGHT_ELBOW]
70
+ left_elbow = results.pose_landmarks.landmark[mp_pose.PoseLandmark.LEFT_ELBOW]
71
 
72
+ # Convert landmark positions to pixel coordinates
73
+ h, w, _ = frame.shape
74
+ right_wrist_coord = (int(right_wrist.x * w), int(right_wrist.y * h))
75
+ left_wrist_coord = (int(left_wrist.x * w), int(left_wrist.y * h))
76
+ right_elbow_coord = (int(right_elbow.x * w), int(right_elbow.y * h))
77
+ left_elbow_coord = (int(left_elbow.x * w), int(left_elbow.y * h))
78
 
79
+ # Calculate the length of the hand region (between wrist and elbow)
80
+ right_hand_length = int(np.sqrt((right_wrist_coord[0] - right_elbow_coord[0])**2 + (right_wrist_coord[1] - right_elbow_coord[1])**2) * 0.5)
81
+ left_hand_length = int(np.sqrt((left_wrist_coord[0] - left_elbow_coord[0])**2 + (left_wrist_coord[1] - left_elbow_coord[1])**2) * 0.5)
82
 
83
+ # Calculate the angle of the hand for rotation
84
+ right_angle = np.degrees(np.arctan2(right_wrist_coord[1] - right_elbow_coord[1], right_wrist_coord[0] - right_elbow_coord[0]))
85
+ left_angle = np.degrees(np.arctan2(left_wrist_coord[1] - left_elbow_coord[1], left_wrist_coord[0] - left_elbow_coord[0]))
86
 
87
+ # Ensure the hand length is positive before resizing
88
+ if right_hand_length > 0:
89
+ # Resize overlay image to fit the hand length
90
+ right_overlay_resized = cv.resize(overlay_img, (right_hand_length, right_hand_length))
91
 
92
+ # Adjust position to overlay the image at the wrist
93
+ right_position = right_wrist_coord
94
 
95
+ # Overlay the image on the right hand with rotation following the arm direction
96
+ alpha_mask = right_overlay_resized[:, :, 3] / 255.0
97
+ overlay_image_alpha_rotated(frame, right_overlay_resized[:, :, :3], right_position, alpha_mask, right_angle)
98
 
99
+ if left_hand_length > 0:
100
+ # Resize overlay image to fit the hand length
101
+ left_overlay_resized = cv.resize(overlay_img, (left_hand_length, left_hand_length))
102
 
103
+ # Adjust position to overlay the image at the wrist
104
+ left_position = left_wrist_coord
105
 
106
+ # Overlay the image on the left hand with rotation following the arm direction
107
+ alpha_mask = left_overlay_resized[:, :, 3] / 255.0
108
+ overlay_image_alpha_rotated(frame, left_overlay_resized[:, :, :3], left_position, alpha_mask, left_angle)
109
 
 
110
  return frame
111
 
112
+ # Streamlit interface
113
  def main():
114
+ st.title("Webcam Pose Detection with Tattoo Overlay")
115
 
116
+ # Sidebar for file upload
117
  st.sidebar.header("Upload Tattoo Image and Video")
118
+ uploaded_tattoo_img = st.sidebar.file_uploader("Upload Tattoo Image", type=["png", "jpg", "jpeg"])
119
  uploaded_video = st.sidebar.file_uploader("Upload Video File", type=["mp4", "mov", "avi"])
120
 
121
  if uploaded_tattoo_img and uploaded_video:
122
+ # Load the uploaded tattoo image
123
+ file_bytes = np.frombuffer(uploaded_tattoo_img.read(), np.uint8)
124
+ tattoo_img = cv.imdecode(file_bytes, cv.IMREAD_UNCHANGED)
125
 
126
+ # If the image is in JPG format (no alpha channel), add an alpha channel
127
+ if tattoo_img.shape[2] == 3: # Check if image has only 3 channels (BGR)
128
+ tattoo_img = add_alpha_channel(tattoo_img)
129
+
130
+ # Checkbox to start the processing
131
  run = st.checkbox('Run')
132
 
133
  if run:
134
+ # Temporary file to store the uploaded video
135
  tfile = tempfile.NamedTemporaryFile(delete=False)
136
  tfile.write(uploaded_video.read())
137
 
138
+ # Video capture
139
  cap = cv.VideoCapture(tfile.name)
140
 
141
  stframe = st.empty()
 
145
  if not ret:
146
  break
147
 
148
+ # Perform pose detection and overlay
149
  frame = poseDetector(frame, tattoo_img)
150
+
151
+ # Convert the frame to RGB for display in Streamlit
152
  frame = cv.cvtColor(frame, cv.COLOR_BGR2RGB)
153
  stframe.image(frame, channels="RGB")
154
 
graph_opt.pb DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:51f84ea82b3d0143dd4cf362e018c125e832c64771908ee8766fbd8b0328008d
3
- size 7804434