<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Mert ALP</title>
    <description>The latest articles on DEV Community by Mert ALP (@schelterhub).</description>
    <link>https://dev.to/schelterhub</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4159926%2F4f399f83-4edc-468b-a1e5-cf5b6187a8b9.jpg</url>
      <title>DEV Community: Mert ALP</title>
      <link>https://dev.to/schelterhub</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/schelterhub"/>
    <language>en</language>
    <item>
      <title>Turn long videos into short clips — without uploading your videos.</title>
      <dc:creator>Mert ALP</dc:creator>
      <pubDate>Thu, 08 Oct 2026 06:23:09 +0000</pubDate>
      <link>https://dev.to/schelterhub/turn-long-videos-into-short-clips-without-uploading-your-videos-394n</link>
      <guid>https://dev.to/schelterhub/turn-long-videos-into-short-clips-without-uploading-your-videos-394n</guid>
      <description>&lt;p&gt;LunarClip finds the best moments, reframes them to 9:16,1:1,4:5 and adds captions without uploading your video.&lt;/p&gt;

&lt;p&gt;Built for Windows. 🔒&lt;br&gt;
Local AI Video Clipper Tool&lt;br&gt;
&lt;strong&gt;&lt;a href="https://lunarclip.com/" rel="noopener noreferrer"&gt;🌐 LunarClip&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>One crop does not fit all: framing vertical clips by video type, on the user's PC</title>
      <dc:creator>Mert ALP</dc:creator>
      <pubDate>Tue, 06 Oct 2026 09:54:57 +0000</pubDate>
      <link>https://dev.to/schelterhub/one-crop-does-not-fit-all-framing-vertical-clips-by-video-type-on-the-users-pc-49ij</link>
      <guid>https://dev.to/schelterhub/one-crop-does-not-fit-all-framing-vertical-clips-by-video-type-on-the-users-pc-49ij</guid>
      <description>&lt;p&gt;We build LunarClip, a Windows app that turns long videos into short vertical clips. The obvious way to make a 9:16 clip from a 16:9 video is a center crop, or a crop that follows the biggest face. Both work for a talking head and fail almost everywhere else. This post covers the two decisions that shaped the app most: the crop depends on what the video is about, and the heavy work happens on the user's own computer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why one crop rule is not enough
&lt;/h2&gt;

&lt;p&gt;A 9:16 window over a 16:9 frame keeps only about a third of the width. What belongs in that third depends on the genre:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In a &lt;strong&gt;stream&lt;/strong&gt;, the important things are in two places at once: the streamer's webcam in a corner and the gameplay in the middle. Any single crop loses one of them.&lt;/li&gt;
&lt;li&gt;In &lt;strong&gt;sports&lt;/strong&gt;, the subject is the ball and the players around it, not the largest face. A face-following crop happily tracks a spectator.&lt;/li&gt;
&lt;li&gt;In a &lt;strong&gt;podcast&lt;/strong&gt;, two people talk back and forth. A crop that jumps to whoever spoke last feels nervous, and a crop that sits on one person misses half the conversation.&lt;/li&gt;
&lt;li&gt;In an &lt;strong&gt;everyday or food video&lt;/strong&gt;, the important object is often not a person at all: the pan, the plate, the product.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So the app has a framing rule per video type.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4ljdkfvegtjrkseuzn8s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4ljdkfvegtjrkseuzn8s.png" alt="Four video types, four different crops" width="799" height="491"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Rule&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Game&lt;/td&gt;
&lt;td&gt;The streamer's webcam goes on top showing only the person, and the gameplay fills the rest, wherever the webcam sits in the source.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sports&lt;/td&gt;
&lt;td&gt;Follows the ball and the players around it, switching between close-up, medium, wide and full-frame shots.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Podcast&lt;/td&gt;
&lt;td&gt;Split screen for back-and-forth, one speaker for monologues, and a wide shot when everyone talks. Switching is deliberately calm.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Normal&lt;/td&gt;
&lt;td&gt;No automatic split. Keeps food and products in frame, and still zooms in on a person talking to camera.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Auto&lt;/td&gt;
&lt;td&gt;Picks the type from the title, tags, description and sound, and falls back to Normal when it is unsure.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Two things we learned while building these rules:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Genre detection should fail safe.&lt;/strong&gt; When Auto cannot tell what a video is, it falls back to the plainest rule. A wrong split screen on a cooking video looks far worse than a slightly loose crop.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Calm beats clever.&lt;/strong&gt; On podcasts, calm speaker switching reads better than a crop that chases every short "yeah". Fewer cuts, each one for a reason.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Why it runs on your PC
&lt;/h2&gt;

&lt;p&gt;The second decision was where the work happens. Uploading a two-hour video to a server before anything can start means a long upload, a queue and a copy of the video on someone else's machine. So everything that touches the video runs locally.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4nzwz2lasn7vwprhai9m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4nzwz2lasn7vwprhai9m.png" alt="What runs on the PC and what goes to the server" width="800" height="366"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On the user's computer:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;speech-to-text with a local speech model (downloaded once, with the first transcription),&lt;/li&gt;
&lt;li&gt;shot and face analysis and the framing rules above,&lt;/li&gt;
&lt;li&gt;captions and hook text,&lt;/li&gt;
&lt;li&gt;rendering, on a recent NVIDIA, AMD or Intel graphics card if there is one, otherwise on the processor.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Only one step uses the server: picking the strongest moments. For that, the app sends short transcript excerpts of candidate clips (text, timestamps and scores), and the server returns its picks with titles and captions. The video, the audio and the finished clips never leave the computer.&lt;/p&gt;

&lt;p&gt;The trade-offs are real and worth stating:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the app needs an internet connection while a project is being made, because moment picking happens on the server;&lt;/li&gt;
&lt;li&gt;processing speed depends on the user's hardware instead of a data-center GPU;&lt;/li&gt;
&lt;li&gt;it is a Windows app for now.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What the user gets in exchange is no upload, no shared queue, and no copy of their video anywhere else.&lt;/p&gt;

&lt;h2&gt;
  
  
  Takeaway
&lt;/h2&gt;

&lt;p&gt;If you are building anything that reframes video, decide early what your subject is for each kind of footage. "Follow the biggest face" is a rule for talking heads, not a general one. And if most of the pipeline can run on the user's machine, the privacy story becomes a property of the architecture rather than a promise in a policy.&lt;br&gt;
&lt;a href="//lunarclip.com"&gt;LunarClip&lt;/a&gt;&lt;/p&gt;

</description>
      <category>computervision</category>
      <category>video</category>
      <category>privacy</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Five video metrics that lied to us (and the one-frame rule that caught them)</title>
      <dc:creator>Mert ALP</dc:creator>
      <pubDate>Sat, 03 Oct 2026 14:46:07 +0000</pubDate>
      <link>https://dev.to/schelterhub/five-video-metrics-that-lied-to-us-and-the-one-frame-rule-that-caught-them-47gf</link>
      <guid>https://dev.to/schelterhub/five-video-metrics-that-lied-to-us-and-the-one-frame-rule-that-caught-them-47gf</guid>
      <description>&lt;p&gt;A broken pixel metric does not crash. It keeps returning numbers. The numbers are in range, the table looks consistent, the histogram has a sensible shape, and you write a conclusion under it.&lt;/p&gt;

&lt;p&gt;We build a tool that reframes landscape video into vertical clips, so we measure a lot of things per frame: where the face is, where the captions sit, whether the frame is empty, who is speaking. Five of those measurements were wrong in ways that no other number could have told us. Each time, what exposed the problem was opening one frame and looking at it.&lt;/p&gt;

&lt;p&gt;This post covers the five failures and the rule we adopted afterwards.&lt;/p&gt;

&lt;h2&gt;
  
  
  Background: the &lt;code&gt;fit&lt;/code&gt; layout
&lt;/h2&gt;

&lt;p&gt;Most of these failures share one cause, so the layout needs explaining first.&lt;/p&gt;

&lt;p&gt;When a 16:9 source goes into a 9:16 output, there are two broad options. &lt;code&gt;fill&lt;/code&gt; crops the source to a tall window. &lt;code&gt;fit&lt;/code&gt; keeps the whole source visible: the 16:9 picture sits in the middle of the vertical frame, and the empty bands above and below are filled with a blurred, enlarged copy of the same video.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;+-----------+
| blurred   |   enlarged, blurred copy of the video
| copy      |
+-----------+
|           |
|  real     |   the actual 16:9 picture
|  picture  |
|           |
+-----------+
| blurred   |
| copy      |
+-----------+
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The padding is useful visually. For measurement it is a trap, because:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;It is not empty. It is the video, scaled up and blurred.&lt;/li&gt;
&lt;li&gt;Anything a detector can find in the real picture, it can often find in the padding too, at a larger size.&lt;/li&gt;
&lt;li&gt;Whole horizontal bands of the frame belong to the padding, not to the content.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Keep that in mind for the metrics below.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. The caption band detector
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What we thought it measured:&lt;/strong&gt; the vertical position of the caption band, so we could keep subjects clear of it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What it measured:&lt;/strong&gt; a loose contour-based detector responds to any dense, high-contrast edge structure near the bottom of the frame. In practice that meant a broadcaster's watermark, plus the outlines of hands and plates. The "band" appeared to jump around from frame to frame because the detector was latching onto different objects.&lt;/p&gt;

&lt;p&gt;Nothing errored. We got a position for every frame.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. The identity histogram
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What we thought it measured:&lt;/strong&gt; whether the person in frame was the same person, by comparing colour histograms of a region.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What it measured:&lt;/strong&gt; we sampled the region just below the detected face, assuming it would be a shirt or torso. It was frequently a hand, a napkin or a plate. The histogram changed substantially while the person stayed exactly the same, and stayed flat when a different person wore similar colours.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. The mouth and eye motion ratio
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What we thought it measured:&lt;/strong&gt; whether someone is speaking, using landmark motion around the mouth normalised by the eyes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;mouth_activity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;landmarks_seq&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# landmarks_seq: per-frame (mouth_points, eye_points)
&lt;/span&gt;    &lt;span class="n"&gt;ratios&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;mouth&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;eyes&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;landmarks_seq&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;mouth_motion&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ptp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mouth&lt;/span&gt;&lt;span class="p"&gt;[:,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;        &lt;span class="c1"&gt;# vertical spread
&lt;/span&gt;        &lt;span class="n"&gt;eye_scale&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;linalg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;norm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;eyes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;eyes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
        &lt;span class="n"&gt;ratios&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mouth_motion&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;eye_scale&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;float&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mean&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ratios&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;What it measured:&lt;/strong&gt; jaw movement. On cooking and eating footage, the frame with the highest "speaking" score was the clearest example of someone chewing. The metric is perfectly good at detecting that a mouth is moving. It cannot tell you why.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. The empty-frame band
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What we thought it measured:&lt;/strong&gt; whether the frame is empty (no subject), by checking how much the pixels in a vertical band deviate from a flat background.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What it measured:&lt;/strong&gt; the band we picked fell inside the &lt;code&gt;fit&lt;/code&gt; padding. The padding is a blurred copy of the video, and in a dark scene a blurred dark video is close to one flat colour. So dark scenes with a clearly visible subject scored as empty.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;band&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;frame&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.15&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.55&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;span class="n"&gt;deviation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;band&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reshape&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;std&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;axis&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;mean&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="c1"&gt;# low deviation -&amp;gt; "empty"
# ...in a layout where that band is blurred padding
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  5. Face area from a face detector
&lt;/h2&gt;

&lt;p&gt;This was the clearest one, and it used a good, widely available detector (YuNet, via OpenCV).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What we thought it measured:&lt;/strong&gt; how large the face is in the frame, as a fraction of frame area. We take the largest box per frame.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;detector&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cv2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FaceDetectorYN&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model_path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;faces&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;detector&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;detect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;frame&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;faces&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bw&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bh&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;faces&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;])[:&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;face_area&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bw&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;bh&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;What it measured:&lt;/strong&gt; in the &lt;code&gt;fit&lt;/code&gt; layout, the padding contains an enlarged copy of the speaker, and the detector found that face too. Because we took the largest box per frame, the enlarged copy won. In 13 of 17 sampled frames, the selected box was in the padding. The reported face area was 14.77% against a real value of about 0.15%.&lt;/p&gt;

&lt;p&gt;Again: valid boxes, valid confidence scores, and a believable-looking distribution.&lt;/p&gt;

&lt;h2&gt;
  
  
  What these have in common
&lt;/h2&gt;

&lt;p&gt;None of the five raised an error. Each returned values in the expected range. And each was wrong in a way that a second metric would not have revealed, because a second metric computed on the same frames would have inherited the same mistake (the padding, the watermark, the hand).&lt;/p&gt;

&lt;p&gt;What does reveal the problem is a single frame with the measurement drawn on it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The rule
&lt;/h2&gt;

&lt;p&gt;Before a pixel metric goes into a report or a decision, look at at least one frame with the measurement overlaid. Generate a contact sheet or a strip, open it, and look.&lt;/p&gt;

&lt;p&gt;It does not need to be a heavy process. A helper like this is enough:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;overlay_and_save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;frame&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;boxes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;out&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;frame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;copy&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nf"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;boxes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;cv2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;rectangle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;cv2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;imwrite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then open the file. The step that matters is the last one: a person looks at it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Checklist
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Look at the highest-scoring and lowest-scoring frames for the metric. Extremes show failures fastest; our "most talkative" frame was the chewing one.&lt;/li&gt;
&lt;li&gt;If the layout has padding, detect the padded frames and mask the padding, or widen the measurement region to the whole frame. Do not measure inside a band that may be blurred filler.&lt;/li&gt;
&lt;li&gt;Keep watermarks, broadcaster graphics and burned-in lower thirds out of the measurement region.&lt;/li&gt;
&lt;li&gt;Apply the same detector with the same settings to both sides of any comparison. Do not use a loose detector for coverage on one side and a strict one for position on the other. If one output has black padding and another has blurred padding, a comparison that ignores this is biased.&lt;/li&gt;
&lt;li&gt;Show the contact sheet to someone else. Writing it to disk is not delivering it, and a second pair of eyes catches what the author has stopped seeing.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Disclosure
&lt;/h2&gt;

&lt;p&gt;I work on LunarClip; these measurements come from testing its reframing. This article was written with AI assistance from our own measurement notes.&lt;/p&gt;

&lt;p&gt;The rule itself is tool-agnostic. If you run a metric over video and have never looked at the frame it picked, pick the worst-scoring one today and open it.&lt;/p&gt;

</description>
      <category>computervision</category>
      <category>video</category>
      <category>testing</category>
      <category>showdev</category>
    </item>
  </channel>
</rss>
