Rawal Khirodkar commited on
Commit
397e140
·
1 Parent(s): b0602ac

Pose: match seg/normal aesthetic (Helvetica, gradient title, badges, ImageSlider, hero examples, 0.4B-only preload)

Browse files
.gitattributes CHANGED
@@ -34,3 +34,5 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
  *.png filter=lfs diff=lfs merge=lfs -text
 
 
 
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
  *.png filter=lfs diff=lfs merge=lfs -text
37
+ *.jpg filter=lfs diff=lfs merge=lfs -text
38
+ *.jpeg filter=lfs diff=lfs merge=lfs -text
app.py CHANGED
@@ -1,11 +1,7 @@
1
  """Sapiens2 pose-estimation Gradio Space.
2
 
3
- Top-down 308-keypoint pose: RTMDet finds people, Sapiens2 estimates keypoints
4
  on each crop, and we draw skeleton + keypoints with the GOLIATH palette.
5
-
6
- All checkpoints are pulled from HuggingFace at startup so this Space repo
7
- stays small. The eager pre-load below warms the cache for the detector and
8
- all 4 pose sizes during boot, so user requests are instant.
9
  """
10
 
11
  # Block mmpretrain: mmdet's reid modules try `import mmpretrain` inside
@@ -14,8 +10,7 @@ all 4 pose sizes during boot, so user requests are instant.
14
  import sys
15
  sys.modules["mmpretrain"] = None
16
 
17
- # Use the vendored sapiens2 source (the upstream package pins requires-python
18
- # to >=3.12; we run on 3.10 here, so we sys.path-import the source instead).
19
  import os
20
  sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
21
 
@@ -46,7 +41,6 @@ from pose_render_utils import visualize_keypoints
46
  ASSETS_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), "assets")
47
  CONFIGS_DIR = os.path.join(ASSETS_DIR, "configs")
48
 
49
- # Sapiens2 pose checkpoints — fetched from HF model repos at startup.
50
  POSE_MODELS = {
51
  "0.4B": {
52
  "repo": "facebook/sapiens2-pose-0.4b",
@@ -69,7 +63,7 @@ POSE_MODELS = {
69
  "config": os.path.join(CONFIGS_DIR, "sapiens2_5b_keypoints308_shutterstock_goliath_3po-1024x768.py"),
70
  },
71
  }
72
- DEFAULT_SIZE = "1B"
73
 
74
  DETECTOR_MODEL_ID = "facebook/detr-resnet-50" # COCO person = label 1
75
 
@@ -79,7 +73,7 @@ NMS_THR = 0.3
79
 
80
 
81
  # -----------------------------------------------------------------------------
82
- # Model cache (load once, reuse across requests)
83
 
84
  _pose_model_cache: dict = {}
85
  _detector_cache: dict = {}
@@ -116,13 +110,13 @@ def _get_pose_model(size: str):
116
  return _pose_model_cache[size]
117
 
118
 
119
- # -----------------------------------------------------------------------------
120
- # Eager pre-load: download + warm-load detector + all pose sizes at startup so
121
- # the first user (and every user thereafter) gets an instant response.
122
- print("[startup] pre-loading detector + all pose sizes ...")
123
  _get_detector()
124
- for _size in POSE_MODELS:
125
- _get_pose_model(_size)
 
126
  print("[startup] ready.")
127
 
128
 
@@ -135,14 +129,14 @@ def _detect_persons(image_rgb: np.ndarray) -> np.ndarray:
135
  inputs = proc(images=pil_img, return_tensors="pt").to(DEVICE)
136
  with torch.no_grad():
137
  outputs = model(**inputs)
138
- target_sizes = torch.tensor([image_rgb.shape[:2]], device=DEVICE) # (h, w)
139
  results = proc.post_process_object_detection(
140
  outputs, target_sizes=target_sizes, threshold=BBOX_THR
141
  )[0]
142
- person_mask = results["labels"] == 1 # COCO person
143
- boxes = results["boxes"][person_mask].cpu().numpy() # (N, 4) x1,y1,x2,y2
144
  scores = results["scores"][person_mask].cpu().numpy().reshape(-1, 1)
145
- bboxes = np.concatenate([boxes, scores], axis=1) # (N, 5)
146
  bboxes = bboxes[nms(bboxes, NMS_THR), :4]
147
  if len(bboxes) == 0:
148
  h, w = image_rgb.shape[:2]
@@ -161,12 +155,12 @@ def _estimate_pose(image_bgr: np.ndarray, bboxes: np.ndarray, model) -> Tuple[Li
161
 
162
  inputs = torch.cat(inputs_list, dim=0)
163
  with torch.no_grad():
164
- pred = model(inputs) # (B, K, h, w) heatmaps
165
 
166
  pred = pred.cpu().numpy()
167
  keypoints, scores = [], []
168
  for i, sample in enumerate(samples_list):
169
- kpts_i, scr_i = model.codec.decode(pred[i]) # (1, K, 2), (1, K)
170
  meta = sample["meta"]
171
  kpts_i = kpts_i / meta["input_size"] * meta["bbox_scale"] + meta["bbox_center"] - 0.5 * meta["bbox_scale"]
172
  keypoints.append(kpts_i[0])
@@ -182,7 +176,8 @@ def predict(image: Image.Image, size: str, kpt_thr: float):
182
  if image is None:
183
  return None, None
184
 
185
- image_rgb = np.array(image.convert("RGB"))
 
186
  image_bgr = cv2.cvtColor(image_rgb, cv2.COLOR_RGB2BGR)
187
 
188
  bboxes = _detect_persons(image_rgb)
@@ -202,6 +197,7 @@ def predict(image: Image.Image, size: str, kpt_thr: float):
202
  kpt_color=meta["keypoint_colors"],
203
  link_color=meta["skeleton_link_colors"],
204
  )
 
205
 
206
  instances = [
207
  {
@@ -215,7 +211,8 @@ def predict(image: Image.Image, size: str, kpt_thr: float):
215
  json.dump({"instances": instances}, f)
216
  json_path = f.name
217
 
218
- return Image.fromarray(vis_rgb), json_path
 
219
 
220
 
221
  # -----------------------------------------------------------------------------
@@ -227,30 +224,84 @@ EXAMPLES = sorted(
227
  if n.lower().endswith((".jpg", ".jpeg", ".png"))
228
  )
229
 
230
- with gr.Blocks(title="Sapiens2 Pose", theme=gr.themes.Default()) as demo:
231
- gr.Markdown(
232
- "# Sapiens2: Pose Estimation\n"
233
- "### ICLR 2026\n"
234
- "Top-down 308-keypoint human pose. RTMDet finds people; Sapiens2 estimates keypoints.\n\n"
235
- "[Code](https://github.com/facebookresearch/sapiens2) · "
236
- "[Models](https://huggingface.co/facebook/sapiens2) · "
237
- "[Paper](https://openreview.net/pdf?id=IVAlYCqdvW)"
238
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
239
  with gr.Row():
240
- with gr.Column():
241
- inp = gr.Image(label="Input", type="pil")
242
- with gr.Row():
243
- size = gr.Radio(
244
- choices=list(POSE_MODELS.keys()),
245
- value=DEFAULT_SIZE,
246
- label="Model size",
247
- )
248
- thr = gr.Slider(0.0, 1.0, value=0.3, step=0.05, label="Keypoint threshold")
249
- run = gr.Button("Run", variant="primary")
250
- gr.Examples(examples=EXAMPLES, inputs=inp, examples_per_page=14)
251
- with gr.Column():
252
- out_img = gr.Image(label="Pose-308 result", type="pil")
253
- out_json = gr.File(label="Keypoints (.json)")
254
 
255
  run.click(predict, inputs=[inp, size, thr], outputs=[out_img, out_json])
256
 
 
1
  """Sapiens2 pose-estimation Gradio Space.
2
 
3
+ Top-down 308-keypoint pose: DETR finds people, Sapiens2 estimates keypoints
4
  on each crop, and we draw skeleton + keypoints with the GOLIATH palette.
 
 
 
 
5
  """
6
 
7
  # Block mmpretrain: mmdet's reid modules try `import mmpretrain` inside
 
10
  import sys
11
  sys.modules["mmpretrain"] = None
12
 
13
+ # Use the vendored sapiens2 source.
 
14
  import os
15
  sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
16
 
 
41
  ASSETS_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), "assets")
42
  CONFIGS_DIR = os.path.join(ASSETS_DIR, "configs")
43
 
 
44
  POSE_MODELS = {
45
  "0.4B": {
46
  "repo": "facebook/sapiens2-pose-0.4b",
 
63
  "config": os.path.join(CONFIGS_DIR, "sapiens2_5b_keypoints308_shutterstock_goliath_3po-1024x768.py"),
64
  },
65
  }
66
+ DEFAULT_SIZE = "0.4B" # iteration mode — only this is preloaded; others lazy-load on click
67
 
68
  DETECTOR_MODEL_ID = "facebook/detr-resnet-50" # COCO person = label 1
69
 
 
73
 
74
 
75
  # -----------------------------------------------------------------------------
76
+ # Model cache
77
 
78
  _pose_model_cache: dict = {}
79
  _detector_cache: dict = {}
 
110
  return _pose_model_cache[size]
111
 
112
 
113
+ # Iteration mode: only preload the default (0.4B) for fast Space boot.
114
+ # Re-enable full preload by uncommenting the loop below.
115
+ print("[startup] pre-loading detector + 0.4B (iteration mode) ...")
 
116
  _get_detector()
117
+ _get_pose_model(DEFAULT_SIZE)
118
+ # for _size in POSE_MODELS:
119
+ # _get_pose_model(_size)
120
  print("[startup] ready.")
121
 
122
 
 
129
  inputs = proc(images=pil_img, return_tensors="pt").to(DEVICE)
130
  with torch.no_grad():
131
  outputs = model(**inputs)
132
+ target_sizes = torch.tensor([image_rgb.shape[:2]], device=DEVICE)
133
  results = proc.post_process_object_detection(
134
  outputs, target_sizes=target_sizes, threshold=BBOX_THR
135
  )[0]
136
+ person_mask = results["labels"] == 1
137
+ boxes = results["boxes"][person_mask].cpu().numpy()
138
  scores = results["scores"][person_mask].cpu().numpy().reshape(-1, 1)
139
+ bboxes = np.concatenate([boxes, scores], axis=1)
140
  bboxes = bboxes[nms(bboxes, NMS_THR), :4]
141
  if len(bboxes) == 0:
142
  h, w = image_rgb.shape[:2]
 
155
 
156
  inputs = torch.cat(inputs_list, dim=0)
157
  with torch.no_grad():
158
+ pred = model(inputs)
159
 
160
  pred = pred.cpu().numpy()
161
  keypoints, scores = [], []
162
  for i, sample in enumerate(samples_list):
163
+ kpts_i, scr_i = model.codec.decode(pred[i])
164
  meta = sample["meta"]
165
  kpts_i = kpts_i / meta["input_size"] * meta["bbox_scale"] + meta["bbox_center"] - 0.5 * meta["bbox_scale"]
166
  keypoints.append(kpts_i[0])
 
176
  if image is None:
177
  return None, None
178
 
179
+ image_pil = image.convert("RGB")
180
+ image_rgb = np.array(image_pil)
181
  image_bgr = cv2.cvtColor(image_rgb, cv2.COLOR_RGB2BGR)
182
 
183
  bboxes = _detect_persons(image_rgb)
 
197
  kpt_color=meta["keypoint_colors"],
198
  link_color=meta["skeleton_link_colors"],
199
  )
200
+ vis_pil = Image.fromarray(vis_rgb)
201
 
202
  instances = [
203
  {
 
211
  json.dump({"instances": instances}, f)
212
  json_path = f.name
213
 
214
+ # Slider value: (left=input RGB, right=keypoints+skeleton overlay).
215
+ return (image_pil, vis_pil), json_path
216
 
217
 
218
  # -----------------------------------------------------------------------------
 
224
  if n.lower().endswith((".jpg", ".jpeg", ".png"))
225
  )
226
 
227
+ CUSTOM_CSS = """
228
+ :root, body, .gradio-container, button, input, select, textarea,
229
+ .gradio-container *:not(code):not(pre) {
230
+ font-family: "Helvetica Neue", Helvetica, Arial, sans-serif !important;
231
+ -webkit-font-smoothing: antialiased;
232
+ -moz-osx-font-smoothing: grayscale;
233
+ }
234
+
235
+ #title { text-align: center; font-size: 44px; font-weight: 700;
236
+ letter-spacing: -0.01em; margin: 28px 0 4px;
237
+ background: linear-gradient(90deg, #1d4ed8 0%, #6d28d9 50%, #be185d 100%);
238
+ -webkit-background-clip: text; -webkit-text-fill-color: transparent;
239
+ background-clip: text; }
240
+ #subtitle { text-align: center; font-size: 12px; color: #64748b;
241
+ letter-spacing: 0.18em; margin: 0 0 14px; text-transform: uppercase;
242
+ font-weight: 500; }
243
+ #badges { display: flex; justify-content: center; flex-wrap: wrap;
244
+ gap: 8px; margin: 0 0 32px; }
245
+ .pill { display: inline-flex; align-items: center; gap: 6px;
246
+ padding: 7px 14px; border-radius: 999px;
247
+ background: #f1f5f9; color: #0f172a !important;
248
+ font-size: 13px; font-weight: 500; letter-spacing: 0.01em;
249
+ text-decoration: none !important; border: 1px solid #e2e8f0;
250
+ transition: background 150ms ease, transform 150ms ease, border-color 150ms ease; }
251
+ .pill:hover { background: #0f172a; color: #f8fafc !important;
252
+ border-color: #0f172a; transform: translateY(-1px); }
253
+ .pill svg { width: 14px; height: 14px; }
254
+ """
255
+
256
+ HEADER_HTML = """
257
+ <div id="title">Sapiens2: Pose</div>
258
+ <div id="subtitle">ICLR 2026</div>
259
+ <div id="badges">
260
+ <a class="pill" href="https://github.com/facebookresearch/sapiens2" target="_blank" rel="noopener">
261
+ <svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 .3a12 12 0 0 0-3.8 23.4c.6.1.8-.3.8-.6v-2c-3.3.7-4-1.6-4-1.6-.6-1.4-1.4-1.8-1.4-1.8-1.1-.7.1-.7.1-.7 1.3.1 2 1.3 2 1.3 1.1 1.9 3 1.4 3.7 1 .1-.8.4-1.4.8-1.7-2.7-.3-5.5-1.3-5.5-5.9 0-1.3.5-2.4 1.3-3.2-.1-.4-.6-1.6.1-3.2 0 0 1-.3 3.3 1.2a11.5 11.5 0 0 1 6 0c2.3-1.5 3.3-1.2 3.3-1.2.7 1.6.2 2.8.1 3.2.8.8 1.3 1.9 1.3 3.2 0 4.6-2.8 5.6-5.5 5.9.4.4.8 1.1.8 2.2v3.3c0 .3.2.7.8.6A12 12 0 0 0 12 .3"/></svg>
262
+ Code
263
+ </a>
264
+ <a class="pill" href="https://huggingface.co/facebook/sapiens2" target="_blank" rel="noopener">
265
+ 🤗 Models
266
+ </a>
267
+ <a class="pill" href="https://openreview.net/pdf?id=IVAlYCqdvW" target="_blank" rel="noopener">
268
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="9" y1="13" x2="15" y2="13"/><line x1="9" y1="17" x2="15" y2="17"/></svg>
269
+ Paper
270
+ </a>
271
+ <a class="pill" href="https://rawalkhirodkar.github.io/sapiens2" target="_blank" rel="noopener">
272
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="2" y1="12" x2="22" y2="12"/><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg>
273
+ Project
274
+ </a>
275
+ </div>
276
+ """
277
+
278
+ with gr.Blocks(title="Sapiens2 Pose", theme=gr.themes.Soft(), css=CUSTOM_CSS) as demo:
279
+ gr.HTML(HEADER_HTML)
280
+
281
+ with gr.Row(equal_height=True):
282
+ inp = gr.Image(label="Input", type="pil", height=640)
283
+ out_img = gr.ImageSlider(
284
+ label="Input ↔ Pose",
285
+ type="pil",
286
+ height=640,
287
+ max_height=640,
288
+ slider_position=50,
289
+ )
290
+
291
  with gr.Row():
292
+ size = gr.Radio(
293
+ choices=list(POSE_MODELS.keys()),
294
+ value=DEFAULT_SIZE,
295
+ label="Model",
296
+ scale=2,
297
+ )
298
+ thr = gr.Slider(0.0, 1.0, value=0.3, step=0.05, label="Keypoint threshold", scale=2)
299
+ run = gr.Button("Run", variant="primary", size="lg", scale=1)
300
+
301
+ gr.Examples(examples=EXAMPLES, inputs=inp, examples_per_page=14)
302
+
303
+ with gr.Accordion("Raw Keypoints", open=False):
304
+ out_json = gr.File(label="Keypoints (.json — bboxes + 308 keypoints + scores per person)")
 
305
 
306
  run.click(predict, inputs=[inp, size, thr], outputs=[out_img, out_json])
307
 
assets/images/68691.png DELETED

Git LFS Details

  • SHA256: fae39e4055c1b297af7068cdddfeeba8d685363281b839d8c5afac1980204b57
  • Pointer size: 132 Bytes
  • Size of remote file: 3.74 MB
assets/images/68956.png DELETED

Git LFS Details

  • SHA256: eee1f27082b10999d0fa848121ecb06cda3386b1a864b9aa0f59ae78261f8908
  • Pointer size: 132 Bytes
  • Size of remote file: 4.15 MB
assets/images/{68204.png → pexels-alex-green-5699868.jpg} RENAMED
File without changes
assets/images/{68210.png → pexels-alimuart-16152561.jpg} RENAMED
File without changes
assets/images/pexels-amresh444-17315601.png DELETED

Git LFS Details

  • SHA256: 4e17ee1b229147e4b52e8348a6ef426bc9e9a2f90738e776e15b26b325abb9b3
  • Pointer size: 132 Bytes
  • Size of remote file: 3.5 MB
assets/images/{68658.png → pexels-anntarazevich-4928706.jpg} RENAMED
File without changes
assets/images/{68666.png → pexels-blue-bird-7242832.jpg} RENAMED
File without changes
assets/images/pexels-cibelebergamim-29948140.jpg ADDED

Git LFS Details

  • SHA256: 3b4b1a5e416b9cae6ac2bcb091f57021a3a023fc26cd4536d6cc0035db96e5a1
  • Pointer size: 131 Bytes
  • Size of remote file: 912 kB
assets/images/pexels-cottonbro-4057693.jpg ADDED

Git LFS Details

  • SHA256: 01038cf1dc126c32ef962bfb5dccd7328549163acf611be25e851caf0de20038
  • Pointer size: 132 Bytes
  • Size of remote file: 2.31 MB
assets/images/pexels-cottonbro-6616678.jpg ADDED

Git LFS Details

  • SHA256: 323d49d6ce428c0cea89decbce13170a1a116f9e3a69985fe88cc8263997695b
  • Pointer size: 132 Bytes
  • Size of remote file: 1.27 MB
assets/images/pexels-gabby-k-6311686.png DELETED

Git LFS Details

  • SHA256: 3f10eded3fb05ab04b963f7b9fd2e183d8d4e81b20569b1c6b0653549639421f
  • Pointer size: 132 Bytes
  • Size of remote file: 3.65 MB
assets/images/pexels-julia-m-cameron-4145040.png DELETED

Git LFS Details

  • SHA256: 459cf0280667b028ffbca16aa11188780d7a0205c0defec02916ff3cbaeecb72
  • Pointer size: 132 Bytes
  • Size of remote file: 2.92 MB
assets/images/pexels-manish-jain-1176829519-31654008.jpg ADDED

Git LFS Details

  • SHA256: 6f6ae7b2e3e71304efdb26466689f2df4a1fe767d8f9c93e3dd79ffd6b4a6f50
  • Pointer size: 132 Bytes
  • Size of remote file: 2.39 MB
assets/images/pexels-marcus-aurelius-6787357.png DELETED

Git LFS Details

  • SHA256: 7d35452f76492125eaf7d5783aa9fd6b0d5990ebe0579fe9dfd58a9d634f4955
  • Pointer size: 132 Bytes
  • Size of remote file: 3.3 MB
assets/images/pexels-marcus-aurelius-6787390.jpg ADDED

Git LFS Details

  • SHA256: 97755a9e98ce0f505085064b4583c530f0bb3d89a9e7e2b3269726f0b9f86730
  • Pointer size: 132 Bytes
  • Size of remote file: 2.57 MB
assets/images/pexels-mehmet-altintas-392989477-31615337.jpg ADDED

Git LFS Details

  • SHA256: 2986083665052e10bbefb7363c5d1e98c3fe0b8cc4e5beb6d6bb7e2cfd01fae4
  • Pointer size: 132 Bytes
  • Size of remote file: 1.92 MB
assets/images/pexels-mihaela-claudia-puscas-836545137-31903488.jpg ADDED

Git LFS Details

  • SHA256: 1b9f09f929eb0eae0f559b766cbe86c01ae0510d36af5d33e776163197123850
  • Pointer size: 132 Bytes
  • Size of remote file: 1.11 MB
assets/images/pexels-mikhail-nilov-8350316.jpg ADDED

Git LFS Details

  • SHA256: 8d20698000ea36f976da4d6267441d88c0f57f63081580e9f25b4eeaf9f4830b
  • Pointer size: 132 Bytes
  • Size of remote file: 1.28 MB
assets/images/pexels-mo-saeed-3616599-5409085.png DELETED

Git LFS Details

  • SHA256: 7c1ca7afd6c2a654e94ef59d5fb56fca4f3cde5fb5216f6b218c34a7b8c143dc
  • Pointer size: 132 Bytes
  • Size of remote file: 3.13 MB
assets/images/pexels-moph-29727777.jpg ADDED

Git LFS Details

  • SHA256: 3afb657363bb4b689796d5f3bc47a9a16084921fbd81832bfffe37c08d3c1d86
  • Pointer size: 131 Bytes
  • Size of remote file: 364 kB
assets/images/pexels-riedelmax-27355495.png DELETED

Git LFS Details

  • SHA256: 4141d2f5f718f162ea1f6710c06b28b5cb51fd69598fde35948f8f3491228164
  • Pointer size: 132 Bytes
  • Size of remote file: 3.73 MB
assets/images/pexels-ruslan-rozanov-174297693-11404049.jpg ADDED

Git LFS Details

  • SHA256: 717fc317962427bb90655269957ca1d8dbcaeba3f45c175e96ef539d385d6e9f
  • Pointer size: 132 Bytes
  • Size of remote file: 2.71 MB
assets/images/pexels-sergeymakashin-5368660.png DELETED

Git LFS Details

  • SHA256: af8f5a8f26dd102d87d94c1be36ec903791fe8e6d951c68ebb9ebcfc6d7397bb
  • Pointer size: 132 Bytes
  • Size of remote file: 4.08 MB
assets/images/pexels-shvetsa-5830936.jpg ADDED

Git LFS Details

  • SHA256: 40a233785b63f15ffeb0d4b468a6827f3f13ab13eee0581c23f682704fc79c91
  • Pointer size: 132 Bytes
  • Size of remote file: 2.86 MB
assets/images/pexels-vazhnik-7562218.jpg ADDED

Git LFS Details

  • SHA256: f33f583df710a12397c55c49c529e2ff17a98dde06f2c2e3d08c51ae03f0e49f
  • Pointer size: 131 Bytes
  • Size of remote file: 826 kB
assets/images/pexels-vinicius-wiesehofer-289347-4219918.png DELETED

Git LFS Details

  • SHA256: a6eef5eee15b81fe65ea95627e9a46040b9889466689b3c1ca6ed273e02fe84f
  • Pointer size: 132 Bytes
  • Size of remote file: 3.63 MB