EtonMu commited on
Commit
1e6ee1b
·
verified ·
1 Parent(s): cb5a6e0

Ship gallery assets as LFS tar (fix broken images)

Browse files
Files changed (4) hide show
  1. app.py +2 -0
  2. pipeline.py +15 -3
  3. static/index.html +53 -12
  4. static_assets.tar +2 -2
app.py CHANGED
@@ -122,6 +122,7 @@ async def process(
122
  tone_strength: float = Form(0.7),
123
  grain_mult: float = Form(1.0),
124
  film_tone_strength: float = Form(0.7),
 
125
  x_access_code: str = Header(default=''),
126
  ):
127
  if not _check_access(x_access_code):
@@ -163,6 +164,7 @@ async def process(
163
  tone_strength=tone_strength,
164
  grain_mult=grain_mult,
165
  film_tone_strength=film_tone_strength,
 
166
  reference_filename=reference.filename or '',
167
  target_filename=target.filename or '',
168
  )
 
122
  tone_strength: float = Form(0.7),
123
  grain_mult: float = Form(1.0),
124
  film_tone_strength: float = Form(0.7),
125
+ halation_mult: float = Form(1.0),
126
  x_access_code: str = Header(default=''),
127
  ):
128
  if not _check_access(x_access_code):
 
164
  tone_strength=tone_strength,
165
  grain_mult=grain_mult,
166
  film_tone_strength=film_tone_strength,
167
+ halation_mult=halation_mult,
168
  reference_filename=reference.filename or '',
169
  target_filename=target.filename or '',
170
  )
pipeline.py CHANGED
@@ -360,6 +360,7 @@ class DeepAnalogPipeline:
360
  tone_strength: float = 0.7,
361
  grain_mult: float = 1.0,
362
  film_tone_strength: float = 0.7,
 
363
  reference_filename: str = '',
364
  target_filename: str = '',
365
  ) -> dict:
@@ -375,10 +376,20 @@ class DeepAnalogPipeline:
375
  grain_size_t = torch.tensor([[fp['grain_size']]], device=self.device)
376
  lum_params_t = torch.tensor([[fp['lum_a'], fp['lum_b'], fp['lum_c']]],
377
  device=self.device)
 
 
 
 
378
  h_threshold_t = torch.tensor([[fp['h_threshold']]], device=self.device)
379
- h_radius_t = torch.tensor([[fp['h_radius']]], device=self.device)
380
- h_intensity_t = torch.tensor([[fp['h_intensity']]], device=self.device)
381
- h_color_bias_t = torch.tensor([fp['h_color_bias']], device=self.device)
 
 
 
 
 
 
382
 
383
  # 1. Color grading via predicted LUT
384
  graded, predicted_lut, _ = self.style_lut(target, ref_224)
@@ -411,6 +422,7 @@ class DeepAnalogPipeline:
411
  'tone_strength': round(float(tone_strength), 4),
412
  'film_tone_strength': round(float(film_tone_strength), 4),
413
  'grain_mult': round(float(grain_mult), 4),
 
414
  })
415
 
416
  return {
 
360
  tone_strength: float = 0.7,
361
  grain_mult: float = 1.0,
362
  film_tone_strength: float = 0.7,
363
+ halation_mult: float = 1.0,
364
  reference_filename: str = '',
365
  target_filename: str = '',
366
  ) -> dict:
 
376
  grain_size_t = torch.tensor([[fp['grain_size']]], device=self.device)
377
  lum_params_t = torch.tensor([[fp['lum_a'], fp['lum_b'], fp['lum_c']]],
378
  device=self.device)
379
+ # Halation control: scales the red-orange glow around bright lights.
380
+ # Intensity scales linearly; radius grows gently; pushing above 1x
381
+ # also warms the glow color for the classic red film bloom.
382
+ hm = max(0.0, float(halation_mult))
383
  h_threshold_t = torch.tensor([[fp['h_threshold']]], device=self.device)
384
+ h_radius_t = torch.tensor([[fp['h_radius'] * (1.0 + 0.35 * max(hm - 1.0, 0.0))]],
385
+ device=self.device)
386
+ h_intensity_t = torch.tensor([[fp['h_intensity'] * hm]], device=self.device)
387
+ bias = list(fp['h_color_bias'])
388
+ if hm > 1.0:
389
+ bias = [bias[0] + 0.5 * (hm - 1.0), # more red
390
+ bias[1],
391
+ bias[2] - 0.3 * (hm - 1.0)] # less blue
392
+ h_color_bias_t = torch.tensor([bias], device=self.device)
393
 
394
  # 1. Color grading via predicted LUT
395
  graded, predicted_lut, _ = self.style_lut(target, ref_224)
 
422
  'tone_strength': round(float(tone_strength), 4),
423
  'film_tone_strength': round(float(film_tone_strength), 4),
424
  'grain_mult': round(float(grain_mult), 4),
425
+ 'halation_mult': round(hm, 4),
426
  })
427
 
428
  return {
static/index.html CHANGED
@@ -144,8 +144,11 @@
144
  }
145
  .controls.visible { display: block; }
146
  .controls h3 { font-size: 12px; letter-spacing: .14em; text-transform: uppercase; color: var(--text-dim); margin-bottom: 16px; }
147
- .sliders { display: grid; grid-template-columns: repeat(3, 1fr); gap: 22px; }
148
  @media (max-width: 720px) { .sliders { grid-template-columns: 1fr; } }
 
 
 
149
  .slider label { display: flex; justify-content: space-between; font-size: 13px; margin-bottom: 8px; color: var(--text); }
150
  .slider label output { color: var(--accent); }
151
  input[type=range] {
@@ -373,29 +376,42 @@
373
  }
374
  .look-card .ov .pname { font-size: 12px; font-weight: 600; color: #fff; line-height: 1.3; }
375
  .look-card .ov .pmeta { font-size: 10.5px; color: rgba(255,255,255,.72); margin-top: 1px; }
 
 
 
 
 
 
 
 
 
 
376
  .look-card a.can-btn {
377
- position: absolute; right: 7px; bottom: 7px; z-index: 3;
378
  display: block; line-height: 0;
379
  filter: drop-shadow(0 1px 3px rgba(0,0,0,.6));
380
  transition: transform .12s;
381
  }
382
  .look-card a.can-btn:hover { transform: scale(1.12); }
383
  .look-card.sel::after {
384
- content: "✓"; position: absolute; top: 7px; right: 7px;
385
  width: 20px; height: 20px; border-radius: 50%;
386
  background: var(--accent); color: #17110a;
387
  font-size: 12px; font-weight: 700;
388
  display: flex; align-items: center; justify-content: center;
389
  }
390
- .input-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 8px; }
 
 
 
391
  .input-grid .in-card {
392
- position: relative; border-radius: 8px; overflow: hidden;
393
  border: 1.5px solid var(--line); cursor: pointer;
394
- transition: border-color .12s;
395
  }
396
- .input-grid .in-card:hover { border-color: var(--text-dim); }
397
  .input-grid .in-card.sel { border-color: var(--accent); }
398
- .input-grid .in-card img { width: 100%; height: 64px; object-fit: cover; display: block; }
399
  .input-grid .in-card.sel::after {
400
  content: "✓"; position: absolute; top: 5px; right: 5px;
401
  width: 17px; height: 17px; border-radius: 50%;
@@ -629,17 +645,38 @@
629
  <h3>Rendering controls</h3>
630
  <div class="sliders">
631
  <div class="slider">
632
- <label>Tone match <output id="toneOut">0.70</output></label>
 
 
 
 
633
  <input type="range" id="toneRange" min="0" max="1" step="0.05" value="0.7">
634
  </div>
635
  <div class="slider">
636
- <label>Film tone <output id="filmOut">0.70</output></label>
 
 
 
 
637
  <input type="range" id="filmRange" min="0" max="1" step="0.05" value="0.7">
638
  </div>
639
  <div class="slider">
640
- <label>Grain <output id="grainOut">1.0×</output></label>
 
 
 
 
641
  <input type="range" id="grainRange" min="0" max="2" step="0.1" value="1.0">
642
  </div>
 
 
 
 
 
 
 
 
 
643
  </div>
644
  </div>
645
 
@@ -891,7 +928,8 @@
891
  // ------------------------------------------------ sliders
892
  [['toneRange', 'toneOut', v => (+v).toFixed(2)],
893
  ['filmRange', 'filmOut', v => (+v).toFixed(2)],
894
- ['grainRange', 'grainOut', v => (+v).toFixed(1) + '×']]
 
895
  .forEach(([r, o, fmt]) => {
896
  $(r).addEventListener('input', () => { $(o).textContent = fmt($(r).value); });
897
  });
@@ -905,6 +943,7 @@
905
  fd.append('tone_strength', $('toneRange').value);
906
  fd.append('film_tone_strength', $('filmRange').value);
907
  fd.append('grain_mult', $('grainRange').value);
 
908
  }
909
  setBusy(true, tgtFile ? 'Rendering — this can take up to a minute for large photos…'
910
  : 'Predicting LUT…');
@@ -1617,6 +1656,8 @@
1617
  card.className = 'look-card';
1618
  card.innerHTML =
1619
  '<img class="bg" loading="lazy" alt="">' +
 
 
1620
  '<div class="ov"><div class="pname"></div><div class="pmeta"></div></div>';
1621
  card.querySelector('.bg').src = imgSrc;
1622
  card.querySelector('.bg').alt = name;
 
144
  }
145
  .controls.visible { display: block; }
146
  .controls h3 { font-size: 12px; letter-spacing: .14em; text-transform: uppercase; color: var(--text-dim); margin-bottom: 16px; }
147
+ .sliders { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 22px; }
148
  @media (max-width: 720px) { .sliders { grid-template-columns: 1fr; } }
149
+ .help .tip img { display: block; width: 100%; border-radius: 6px; margin-top: 9px; }
150
+ .slider .help { width: 15px; height: 15px; font-size: 10px; margin-left: 6px; }
151
+ .slider .tip { width: min(356px, 82vw); }
152
  .slider label { display: flex; justify-content: space-between; font-size: 13px; margin-bottom: 8px; color: var(--text); }
153
  .slider label output { color: var(--accent); }
154
  input[type=range] {
 
376
  }
377
  .look-card .ov .pname { font-size: 12px; font-weight: 600; color: #fff; line-height: 1.3; }
378
  .look-card .ov .pmeta { font-size: 10.5px; color: rgba(255,255,255,.72); margin-top: 1px; }
379
+ .look-card .sprk {
380
+ position: absolute; top: 0; bottom: 0; width: 13px; z-index: 2;
381
+ background-color: #0b0b0e;
382
+ background-image: radial-gradient(rgba(255,255,255,.17) 2.1px, transparent 2.6px);
383
+ background-size: 13px 12px;
384
+ background-position: center;
385
+ }
386
+ .look-card .sprk.l { left: 0; border-right: 1px solid rgba(255,255,255,.05); }
387
+ .look-card .sprk.r { right: 0; border-left: 1px solid rgba(255,255,255,.05); }
388
+ .look-card .ov { padding-left: 22px; padding-right: 22px; }
389
  .look-card a.can-btn {
390
+ position: absolute; right: 17px; bottom: 7px; z-index: 3;
391
  display: block; line-height: 0;
392
  filter: drop-shadow(0 1px 3px rgba(0,0,0,.6));
393
  transition: transform .12s;
394
  }
395
  .look-card a.can-btn:hover { transform: scale(1.12); }
396
  .look-card.sel::after {
397
+ content: "✓"; position: absolute; top: 7px; right: 17px;
398
  width: 20px; height: 20px; border-radius: 50%;
399
  background: var(--accent); color: #17110a;
400
  font-size: 12px; font-weight: 700;
401
  display: flex; align-items: center; justify-content: center;
402
  }
403
+ .input-grid {
404
+ display: grid; grid-template-columns: 1fr; gap: 10px;
405
+ max-height: 640px; overflow-y: auto; padding-right: 5px;
406
+ }
407
  .input-grid .in-card {
408
+ position: relative; border-radius: 9px; overflow: hidden;
409
  border: 1.5px solid var(--line); cursor: pointer;
410
+ transition: border-color .12s, transform .1s;
411
  }
412
+ .input-grid .in-card:hover { border-color: var(--text-dim); transform: translateY(-1px); }
413
  .input-grid .in-card.sel { border-color: var(--accent); }
414
+ .input-grid .in-card img { width: 100%; height: 118px; object-fit: cover; display: block; }
415
  .input-grid .in-card.sel::after {
416
  content: "✓"; position: absolute; top: 5px; right: 5px;
417
  width: 17px; height: 17px; border-radius: 50%;
 
645
  <h3>Rendering controls</h3>
646
  <div class="sliders">
647
  <div class="slider">
648
+ <label><span>Tone match<span class="help">?<span class="tip">Matches your photo’s
649
+ brightness distribution to the reference — shadows, mids and highlights are moved
650
+ to where the film puts them. Left: off · right: full strength.
651
+ <img src="static/help/tone.jpg" alt="Tone match comparison"></span></span></span>
652
+ <output id="toneOut">0.70</output></label>
653
  <input type="range" id="toneRange" min="0" max="1" step="0.05" value="0.7">
654
  </div>
655
  <div class="slider">
656
+ <label><span>Film tone<span class="help">?<span class="tip">Film’s tonal signature:
657
+ lifted blacks (no pure black), a soft highlight roll-off, and the subtle color
658
+ tint film leaves in shadows and highlights. Left: off · right: full strength.
659
+ <img src="static/help/filmtone.jpg" alt="Film tone comparison"></span></span></span>
660
+ <output id="filmOut">0.70</output></label>
661
  <input type="range" id="filmRange" min="0" max="1" step="0.05" value="0.7">
662
  </div>
663
  <div class="slider">
664
+ <label><span>Grain<span class="help">?<span class="tip">How much film grain is
665
+ layered onto the result. 0 = clean, 2 = gritty high-ISO texture.
666
+ Left: 0 · right: 2×.
667
+ <img src="static/help/grain.jpg" alt="Grain comparison"></span></span></span>
668
+ <output id="grainOut">1.0×</output></label>
669
  <input type="range" id="grainRange" min="0" max="2" step="0.1" value="1.0">
670
  </div>
671
+ <div class="slider">
672
+ <label><span>Halation<span class="help">?<span class="tip">The warm red glow film
673
+ creates around bright lights — light scatters off the film base and re-exposes
674
+ the red-sensitive layer. Push past 1× for the classic red night-street bloom.
675
+ Left: off · right: 3×.
676
+ <img src="static/help/halation.jpg" alt="Halation comparison"></span></span></span>
677
+ <output id="halOut">1.0×</output></label>
678
+ <input type="range" id="halRange" min="0" max="3" step="0.1" value="1.0">
679
+ </div>
680
  </div>
681
  </div>
682
 
 
928
  // ------------------------------------------------ sliders
929
  [['toneRange', 'toneOut', v => (+v).toFixed(2)],
930
  ['filmRange', 'filmOut', v => (+v).toFixed(2)],
931
+ ['grainRange', 'grainOut', v => (+v).toFixed(1) + '×'],
932
+ ['halRange', 'halOut', v => (+v).toFixed(1) + '×']]
933
  .forEach(([r, o, fmt]) => {
934
  $(r).addEventListener('input', () => { $(o).textContent = fmt($(r).value); });
935
  });
 
943
  fd.append('tone_strength', $('toneRange').value);
944
  fd.append('film_tone_strength', $('filmRange').value);
945
  fd.append('grain_mult', $('grainRange').value);
946
+ fd.append('halation_mult', $('halRange').value);
947
  }
948
  setBusy(true, tgtFile ? 'Rendering — this can take up to a minute for large photos…'
949
  : 'Predicting LUT…');
 
1656
  card.className = 'look-card';
1657
  card.innerHTML =
1658
  '<img class="bg" loading="lazy" alt="">' +
1659
+ '<span class="sprk l" aria-hidden="true"></span>' +
1660
+ '<span class="sprk r" aria-hidden="true"></span>' +
1661
  '<div class="ov"><div class="pname"></div><div class="pmeta"></div></div>';
1662
  card.querySelector('.bg').src = imgSrc;
1663
  card.querySelector('.bg').alt = name;
static_assets.tar CHANGED
@@ -1,3 +1,3 @@
1
  version https://git-lfs.github.com/spec/v1
2
- oid sha256:d02a18a96d7015feb41ebda93fcbb5a9a745bea9beec39bdcb5c343c2f8cef16
3
- size 69908480
 
1
  version https://git-lfs.github.com/spec/v1
2
+ oid sha256:32ead0e949236298f20f1ddae551e4d2e97d84052a6b8463e7dd489152181ed6
3
+ size 70062080