<?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: Daniël R</title>
    <description>The latest articles on DEV Community by Daniël R (@danil_r_0913f2ae76f4f04d).</description>
    <link>https://dev.to/danil_r_0913f2ae76f4f04d</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3577526%2F320b91ef-e480-4d65-ae58-27626d42d01a.png</url>
      <title>DEV Community: Daniël R</title>
      <link>https://dev.to/danil_r_0913f2ae76f4f04d</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/danil_r_0913f2ae76f4f04d"/>
    <language>en</language>
    <item>
      <title>Augmented reality 3d viewer</title>
      <dc:creator>Daniël R</dc:creator>
      <pubDate>Tue, 21 Oct 2025 13:03:09 +0000</pubDate>
      <link>https://dev.to/danil_r_0913f2ae76f4f04d/augmented-reality-3d-viewer-1310</link>
      <guid>https://dev.to/danil_r_0913f2ae76f4f04d/augmented-reality-3d-viewer-1310</guid>
      <description>&lt;p&gt;Als je wel eens een 3D-design hebt gemaakt, herken je dit vast: je ontwerpt iets zorgvuldig, print het uit... en ontdekt dan dat het toch niet helemaal past of er niet uitziet zoals je had verwacht. Vaak kom je daar pas achter na de eerste of tweede print, wat natuurlijk tijd en materiaal kost. Ik liep tegen precies hetzelfde probleem aan. Daarom heb ik een simpel programma geschreven dat een live camerabeeld combineert met een .stl-bestand, zodat je met &lt;a href="https://nds-nl.wikipedia.org/wiki/Augmented_Reality" rel="noopener noreferrer"&gt;Augmented Reality&lt;/a&gt; direct kunt zien hoe je ontwerp in de echte wereld staat. Zo voorkom je onnodige prints en krijg je sneller een goed beeld van het eindresultaat.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hoe werkt het?
&lt;/h2&gt;

&lt;p&gt;Het idee is simpel: je streamt de camera van je telefoon naar je laptop, laat die live beelden uitlezen in een Python-programma, en laadt daaroverheen een 3D-render van je ontwerp. Vervolgens zorg je ervoor dat je met je muis de render kunt draaien, bewegen en in- en uitzoomen.&lt;/p&gt;

&lt;p&gt;Om dit project te laten werken, moeten de volgende onderdelen goed samenwerken:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Je telefooncamera naar je laptop streamen&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Dit zorgt ervoor dat de live beelden van je telefoon beschikbaar zijn op je laptop. Dit kan bijvoorbeeld via een app of netwerkverbinding die de camerafeed deelt.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Je camerabeeld live laten uitlezen door Python&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Het Python-programma ontvangt de videofeed en kan die in realtime verwerken. Hiervoor gebruiken we een library zoals OpenCV, die videobeelden kan binnenhalen en bewerken.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Je .stl-bestand inlezen en tekenen&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Het 3D-model van je ontwerp, opgeslagen als een .stl-bestand, wordt door het programma ingeladen en omgezet naar een 3D-render. Deze render tekenen we vervolgens over het live camerabeeld heen.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Interactie met het 3D-model mogelijk maken&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Via muisbewegingen kun je het model draaien, verplaatsen en in- en uitzoomen. Dit maakt het mogelijk om je ontwerp vanuit verschillende hoeken en afstanden te bekijken, alsof het echt in de ruimte staat.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Door deze onderdelen samen te brengen ontstaat een augmented reality ervaring waarmee je eenvoudig kunt zien hoe jouw 3D-ontwerp in de echte wereld past — zonder dat je eerst hoeft te printen!&lt;/p&gt;

&lt;h3&gt;
  
  
  Je telefooncamera naar je laptop streamen
&lt;/h3&gt;

&lt;p&gt;Voor het streamen van je camera naar je laptop zijn er ontzettend veel apps en programma’s beschikbaar. Ik heb gekozen voor een simpel en gebruiksvriendelijk programma genaamd &lt;a href="https://iriun.com/" rel="noopener noreferrer"&gt;Iriun&lt;/a&gt;. Dit werkt heel makkelijk: je installeert de software op je Windows-laptop en de bijbehorende app op je telefoon. Vervolgens maak je via USB of via wifi (als je telefoon en laptop op hetzelfde netwerk zitten) automatisch verbinding. Je laptop herkent je telefooncamera dan als een gewone webcam.&lt;/p&gt;

&lt;p&gt;Het mooiste is dat je verder niets hoeft in te stellen. Zolang je de app op je telefoon en het programma op je laptop open hebt, maken ze automatisch verbinding en begint de camerafeed direct te streamen. Super eenvoudig! En er zat deze keer gewoon thee in de beker :)&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.amazonaws.com%2Fuploads%2Farticles%2Fosert1zwslttto3j6o4s.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.amazonaws.com%2Fuploads%2Farticles%2Fosert1zwslttto3j6o4s.png" alt=" " width="698" height="415"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Je camerabeeld laten uitlezen door python
&lt;/h3&gt;

&lt;p&gt;Een erg bekende Python-library die veel wordt gebruikt voor dit soort projecten is &lt;a href="http://opencv.org/" rel="noopener noreferrer"&gt;openCV&lt;/a&gt;. OpenCV is een open-source computer vision library die je kunt gebruiken om eenvoudig en snel dingen te doen zoals beeldherkenning, het bewerken van beelden of bijvoorbeeld het herkennen van ArUco-markers. Er zijn online talloze tutorials te vinden over hoe je je camerabeeld kunt uitlezen met OpenCV, maar gelukkig is het helemaal niet zo ingewikkeld.&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;cap&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="nc"&gt;VideoCapture&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;fx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1280&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;720&lt;/span&gt;
    &lt;span class="n"&gt;cx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fx&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fy&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;
    &lt;span class="n"&gt;camera_matrix&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;array&lt;/span&gt;&lt;span class="p"&gt;([[&lt;/span&gt;&lt;span class="n"&gt;fx&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="n"&gt;cx&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="n"&gt;fy&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;cy&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;0&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;dtype&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;float32&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;dist_coeffs&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;zeros&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="mi"&gt;5&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Zoals hierboven te zien is, is het erg makkelijk om je camerabeeld in Python te gebruiken. Je geeft alleen aan welke camera-input je wilt gebruiken (meestal is &lt;code&gt;0&lt;/code&gt; je standaard webcam, &lt;code&gt;1&lt;/code&gt; is een externe camera) en welke resolutie je instelt.&lt;/p&gt;

&lt;p&gt;Daarnaast kun je, als je meer precisie nodig hebt, een camera matrix toevoegen. Deze matrix beschrijft hoe je camera de echte wereld vertaalt naar pixels. Daarmee kun je vervormingen corrigeren en zorgen dat 3D-objecten realistischer en nauwkeuriger over je camerabeeld worden gelegd. Vooral in augmented reality-projecten, zoals dit, is dat handig om je 3D-modellen netjes te laten aansluiten op de echte wereld.&lt;/p&gt;

&lt;h3&gt;
  
  
  Je .stl-bestand inlezen en tekenen
&lt;/h3&gt;

&lt;p&gt;Het lastigste deel van dit project was het netjes intekenen van de STL-bestanden in het live camerabeeld. Er bestaan namelijk Python-library’s die STL-bestanden als 3D-model kunnen weergeven, maar die openen zich altijd in een eigen 3D-viewer. Dat werkt prima om een ontwerp te bekijken, maar niet als je het model rechtstreeks over een videostream wilt projecteren.&lt;/p&gt;

&lt;p&gt;Om het model in het camerabeeld te krijgen, moet je de 3D-coördinaten van het STL-bestand eerst omrekenen naar 2D-pixelposities. Dat gebeurt met &lt;code&gt;cv2.projectPoints()&lt;/code&gt;. Hiermee worden de punten van het 3D-model geprojecteerd op het camerabeeld, zodat je het ontwerp écht als een overlay ziet.&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;draw_filled_mesh&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;mesh&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;rvec&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tvec&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;camera_matrix&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dist_coeffs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;color&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;150&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;150&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;alpha&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.8&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;vertices&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mesh&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;vertices&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;mesh&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;faces&lt;/span&gt;

    &lt;span class="n"&gt;imgpts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&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="nf"&gt;projectPoints&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vertices&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;rvec&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tvec&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;camera_matrix&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dist_coeffs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;imgpts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;imgpts&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;2&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;astype&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="n"&gt;int32&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;overlay&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="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;face&lt;/span&gt; &lt;span class="ow"&gt;in&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;pts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;imgpts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;face&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;fillPoly&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;overlay&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;pts&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;color&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;addWeighted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;overlay&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;alpha&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="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;alpha&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="n"&gt;frame&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;frame&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;draw_wireframe&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;mesh&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;rvec&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tvec&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;camera_matrix&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dist_coeffs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;color&lt;/span&gt;&lt;span class="o"&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="n"&gt;thickness&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="n"&gt;vertices&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mesh&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;vertices&lt;/span&gt;
    &lt;span class="n"&gt;edges&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mesh&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;edges_unique&lt;/span&gt;

    &lt;span class="n"&gt;imgpts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&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="nf"&gt;projectPoints&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vertices&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;rvec&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tvec&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;camera_matrix&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dist_coeffs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;imgpts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;imgpts&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;2&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;astype&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&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;edge&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;edges&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;pt1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;tuple&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;imgpts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;edge&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="n"&gt;pt2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;tuple&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;imgpts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;edge&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;cv2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;line&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;pt1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pt2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;color&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;thickness&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;frame&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Om het STL-model goed zichtbaar te maken in het camerabeeld gebruik ik twee manieren van tekenen: gevuld en als draadmodel.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;draw_filled_mesh&lt;/code&gt;&lt;br&gt;&lt;br&gt;
Deze functie tekent de &lt;em&gt;vlakken&lt;/em&gt; van het 3D-model in. Eerst worden alle 3D-vertices van het model geprojecteerd naar 2D met &lt;code&gt;cv2.projectPoints()&lt;/code&gt;. Daarna pakt de code de &lt;em&gt;faces&lt;/em&gt; (de driehoekjes waar het model uit is opgebouwd) en vult die één voor één in met een kleur. Door dit over een kopie van het camerabeeld te tekenen en vervolgens half-transparant samen te voegen met &lt;code&gt;cv2.addWeighted()&lt;/code&gt;, krijg je een mooi “glanzend” effect waarbij het model zichtbaar is maar de echte wereld er nog doorheen schijnt.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;draw_wireframe&lt;/code&gt;&lt;br&gt;&lt;br&gt;
Deze functie tekent juist de &lt;em&gt;randen&lt;/em&gt; van het 3D-model. Ook hier worden de 3D-coördinaten omgezet naar 2D-pixels. Daarna loopt de code alle unieke randen van het model af en tekent met &lt;code&gt;cv2.line()&lt;/code&gt; groene lijntjes in het camerabeeld. Dit draadmodel geeft extra detail en maakt de vormen van het model beter herkenbaar.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Door beide functies samen te gebruiken ontstaat een duidelijk en realistisch beeld: je ziet het model als een transparant object met zowel vlakken als lijnen, waardoor het goed opgaat in de echte omgeving.&lt;/p&gt;

&lt;h3&gt;
  
  
  Interactie met het 3D-model mogelijk maken
&lt;/h3&gt;

&lt;p&gt;Om ervoor te zorgen dat je het 3D-model goed kan oriënteren voor waar je het wil plaatsen moet je het kunnen verplaatsen over het camerabeeld, draaien en in en uitzoomen. Om het zo gebruiksvriendelijk te maken is er gekozen om dit allemaal met de muis te doen net zoals je dat zou doen bij een 3d-design programma zoals Fusion of Solidworks.&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="c1"&gt;# Globale variabelen voor muis-rotatie
&lt;/span&gt;&lt;span class="n"&gt;yaw&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pitch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;
&lt;span class="n"&gt;last_x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;last_y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
&lt;span class="n"&gt;dragging_left&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;
&lt;span class="n"&gt;dragging_right&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;

&lt;span class="n"&gt;zoom&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;1.0&lt;/span&gt;

&lt;span class="n"&gt;tx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ty&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tz&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;mouse_callback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&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;flags&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;param&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;global&lt;/span&gt; &lt;span class="n"&gt;yaw&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pitch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;last_x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;last_y&lt;/span&gt;
    &lt;span class="k"&gt;global&lt;/span&gt; &lt;span class="n"&gt;dragging_left&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dragging_right&lt;/span&gt;
    &lt;span class="k"&gt;global&lt;/span&gt; &lt;span class="n"&gt;tx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ty&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tz&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;zoom&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;event&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;EVENT_RBUTTONDOWN&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;dragging_left&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
        &lt;span class="n"&gt;last_x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;last_y&lt;/span&gt; &lt;span class="o"&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="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;event&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;EVENT_LBUTTONDOWN&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;dragging_right&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
        &lt;span class="n"&gt;last_x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;last_y&lt;/span&gt; &lt;span class="o"&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="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;event&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;EVENT_MOUSEMOVE&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;dragging_left&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;dx&lt;/span&gt; &lt;span class="o"&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;last_x&lt;/span&gt;
            &lt;span class="n"&gt;dy&lt;/span&gt; &lt;span class="o"&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;last_y&lt;/span&gt;
            &lt;span class="n"&gt;last_x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;last_y&lt;/span&gt; &lt;span class="o"&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="n"&gt;yaw&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;dx&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;0.01&lt;/span&gt;
            &lt;span class="n"&gt;pitch&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;dy&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;0.01&lt;/span&gt;
           &lt;span class="c1"&gt;# pitch = max(min(pitch, np.pi/2), -np.pi/2)
&lt;/span&gt;
        &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;dragging_right&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;dx&lt;/span&gt; &lt;span class="o"&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;last_x&lt;/span&gt;
            &lt;span class="n"&gt;dy&lt;/span&gt; &lt;span class="o"&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;last_y&lt;/span&gt;
            &lt;span class="n"&gt;last_x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;last_y&lt;/span&gt; &lt;span class="o"&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="n"&gt;tx&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;dx&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;0.001&lt;/span&gt;
            &lt;span class="n"&gt;ty&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="n"&gt;dy&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;0.001&lt;/span&gt;

    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;event&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;EVENT_RBUTTONUP&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;dragging_left&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;

    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;event&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;EVENT_LBUTTONUP&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;dragging_right&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;

    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;event&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;EVENT_MOUSEWHEEL&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;flags&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;zoom&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mf"&gt;0.05&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;zoom&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="mf"&gt;0.05&lt;/span&gt;
        &lt;span class="n"&gt;zoom&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="mf"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;zoom&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;3.0&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_rvec_from_yaw_pitch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;yaw&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pitch&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;Ry&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;array&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;cos&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;yaw&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="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;yaw&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;1&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="p"&gt;[&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;sin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;yaw&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="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cos&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;yaw&lt;/span&gt;&lt;span class="p"&gt;)]])&lt;/span&gt;
    &lt;span class="n"&gt;Rx&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;array&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="mi"&gt;0&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="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="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cos&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pitch&lt;/span&gt;&lt;span class="p"&gt;),&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;sin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pitch&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="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pitch&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;cos&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pitch&lt;/span&gt;&lt;span class="p"&gt;)]])&lt;/span&gt;
    &lt;span class="n"&gt;R&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Ry&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt; &lt;span class="n"&gt;Rx&lt;/span&gt;
    &lt;span class="n"&gt;rvec&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&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="nc"&gt;Rodrigues&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;R&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;rvec&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In de code gebeurt dat via de functie &lt;code&gt;mouse_callback&lt;/code&gt;. Deze luistert naar muisacties en past de positie van het model aan: met de rechtermuisknop draaien, met de linkermuisknop verschuiven en met het scrollwiel in- of uitzoomen. De waarden voor rotatie, positie en zoom worden telkens opgeslagen in variabelen.&lt;/p&gt;

&lt;p&gt;De functie &lt;code&gt;get_rvec_from_yaw_pitch&lt;/code&gt; zet die rotatievariabelen (&lt;code&gt;yaw&lt;/code&gt; en &lt;code&gt;pitch&lt;/code&gt;) vervolgens om naar een rotatiematrix die OpenCV kan gebruiken om het model correct over het camerabeeld te tekenen.&lt;/p&gt;

&lt;h2&gt;
  
  
  Eindresultaat
&lt;/h2&gt;

&lt;p&gt;Als je dit en nog meer code allemaal samen voegt dan komt er een simpel programma uit dat ervoor zorgt dat je .stl bestanden in het echt kan bekijken. Zoals je hieronder kan zien kan dit gebruikt worden om een beeld te krijgen van hoe je ontwerpen in de echte wereld eruit gaan zien.&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.amazonaws.com%2Fuploads%2Farticles%2Fgabajamlndk0a00fop5g.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.amazonaws.com%2Fuploads%2Farticles%2Fgabajamlndk0a00fop5g.png" alt=" " width="651" height="394"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Hierboven heb ik bijvoorbeeld een bakje ontworpen die ik naast het whiteboard wil hangen door de AR viewer weet ik nu ongeveer hoe die eruit gaat zien als ik hem uitprint.&lt;/p&gt;

&lt;h2&gt;
  
  
  Verbeterpunten
&lt;/h2&gt;

&lt;p&gt;Als ik ooit nog aan deze code zou sleutelen zou ik een paar dingen toevoegen.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Betere manier van draaien. Het is op dit moment nog erg lastig om te draaien met alleen de muis.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Andere kleuren toevoegen. Zorgen voor meer kleur zodat je ook meteen dat kan testen wat er mooier uitziet.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Schaal toevoegen. Doormiddel van Aruco markers of iets anders een schaal toevoegen zodat je weet hoe groot je design is op de camera.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Betere cameramatrix. Op dit moment is de cameramatrix niet gekalibreerd op mijn eigen camera. Als dit wel was gedaan was de camera nog preciezer geweest.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>python</category>
      <category>hobby</category>
      <category>mixedreality</category>
    </item>
    <item>
      <title>Knikkerbaan</title>
      <dc:creator>Daniël R</dc:creator>
      <pubDate>Tue, 21 Oct 2025 13:00:03 +0000</pubDate>
      <link>https://dev.to/danil_r_0913f2ae76f4f04d/knikkerbaan-2bi8</link>
      <guid>https://dev.to/danil_r_0913f2ae76f4f04d/knikkerbaan-2bi8</guid>
      <description>&lt;p&gt;Als sinds jong af aan heb ik interesse gehad in knikkerbanen ik maakte ze zelf van lego, kapla of papier. Ik keek altijd naar video’s van enorme knikkerbanen gemaakt van lego en ben zelfs een keer wezen kijken op een conventie. Zelfs nu nog steeds kijk ik vaak video’s van engineers die vette banen maken door ze zelf te ontwerpen en printen(denk vooral aan &lt;a href="https://engineezy.com/?srsltid=AfmBOor4KITOg9yg-J5pmH7U4lmxZTw24ItDRlg_0EOKcUJaeeufEl5U" rel="noopener noreferrer"&gt;Engineazy&lt;/a&gt;). Ik heb altijd al zelf een kleine knikkerbaan willen ontwerpen die doormiddel van een simpel bewegend mechanisme oneindig door kan lopen. In deze blog vertel ik over hoe ik dat eindelijk gedaan heb en waar ik tegenaan ben gelopen.&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.amazonaws.com%2Fuploads%2Farticles%2Fsyg15iwlo1duubdv18ck.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.amazonaws.com%2Fuploads%2Farticles%2Fsyg15iwlo1duubdv18ck.png" alt=" "&gt;&lt;/a&gt;&lt;br&gt;
Het idee is simpel de knikker wordt door de armen over de baan omhoog getild en rolt met zwaartekracht weer naar beneden.&lt;br&gt;&lt;br&gt;
Na het printen van de eerste versie kwam ik achter een groot probleem de muren van de baan waren namelijk 3mm wat niet hoog genoeg was en met een beetje snelheid stuiterde de knikker daar overheen. Daarom is er een 2de versie gemaakt waar alles 3mm omhoog is getild zodat de muren 6mm hoog waren. Dit werkte erg goed.&lt;/p&gt;
&lt;h3&gt;
  
  
  Grote designfout
&lt;/h3&gt;

&lt;p&gt;Als je al een beetje oplettend was kan je zien dat ik een grote designfout heb gemaakt waar ik pas na het printen achter ben gekomen. Zoals je kan zien in de afbeelding draaien alle drie de tandwielen die gebruikt worden om de bal naar boven te helpen dezelfde kant op. Dat zou niet moeten gebeuren de middelste moet eigenlijk de andere kant opdraaien.&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.amazonaws.com%2Fuploads%2Farticles%2Fuooj0lgochbxxpk25p36.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.amazonaws.com%2Fuploads%2Farticles%2Fuooj0lgochbxxpk25p36.png" alt=" "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Omdat ik geen zin had om de complete knikkerbaan opnieuw te ontwerpen en alles opnieuw te printen wat weer een aantal dagen zou duren heb ik ervoor gekozen om een oplossing te bedenken die dit zou verhelpen.&lt;/p&gt;
&lt;h3&gt;
  
  
  De oplossing
&lt;/h3&gt;

&lt;p&gt;De oplossing was niet super netjes maar werkt wel in plaats van 3 tandwielen in het midden is er gekozen voor een grote. Als pluspunt zou alles nu de goede kant opdraaien alleen zou de middelste drager 3 keer zo sloom draaien als de andere twee wat op zichzelf niet een groot probleem is maar er wel minder netjes uitziet.&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.amazonaws.com%2Fuploads%2Farticles%2Fl74ghbme0gnp1gj7umor.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.amazonaws.com%2Fuploads%2Farticles%2Fl74ghbme0gnp1gj7umor.png" alt=" "&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Het eindresultaat
&lt;/h3&gt;

&lt;p&gt;Na een volle prullenbak met test prints en gefaalde ontwerpen is die klaar. Mijn eerste knikkerbaan ik heb er veel van geleerd waaronder dat je soms 5 keer iets checken niet genoeg is en ik ben nog beter geworden in Fusion360.&lt;/p&gt;

&lt;p&gt;

  &lt;iframe src="https://www.youtube.com/embed/B0GWugkAbn0"&gt;
  &lt;/iframe&gt;


&lt;/p&gt;

</description>
      <category>hobby</category>
      <category>3dprinting</category>
      <category>marbles</category>
    </item>
    <item>
      <title>Hart fidget toy</title>
      <dc:creator>Daniël R</dc:creator>
      <pubDate>Tue, 21 Oct 2025 12:57:38 +0000</pubDate>
      <link>https://dev.to/danil_r_0913f2ae76f4f04d/hart-fidget-toy-gde</link>
      <guid>https://dev.to/danil_r_0913f2ae76f4f04d/hart-fidget-toy-gde</guid>
      <description>&lt;p&gt;Ik heb ADHD, best veel ADHD en dat betekend dat ik constant zit te kutten met dingen. ik kras schriften vol ik teken op mezelf en ik tik met pennen. Iets waar ik al veel jaren veel profijt van heb zijn fidget toys deze handige dingen helpen mij met opletten wanneer ik daar zelf moeite mee heb en zorgen er ook voor dat andere mensen niet compleet gestoord worden. Daarom leek het mij leuk om een eigen fidget toy te maken. Ik heb er voor gekozen om een hart te maken met drie tandwielen en initialen erop. Schattig, handig, en leert mij weer werken met nieuwe technieken&lt;/p&gt;

&lt;h3&gt;
  
  
  Design
&lt;/h3&gt;

&lt;p&gt;Ik had als doel om de print zo makkelijk mogelijk te maken en zo weinig mogelijk bewegende onderdelen. Ook moest het robuust zijn en goed kunnen bewegen om dit op te lossen heb ik een systeem bedacht waardoor je de tandwielen in het hart kan klikken zodat ze niet weg kunnen. Zoals je kan zien kan je de tandwielen gemakkelijk in het hart klikken en doordat de er een kleine speling van een halve mm is kunnen de tandwielen bewegen.&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.amazonaws.com%2Fuploads%2Farticles%2Fglmdujq4lmxv3umwnr0z.jpeg" 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.amazonaws.com%2Fuploads%2Farticles%2Fglmdujq4lmxv3umwnr0z.jpeg" alt=" " width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Na het eerste design merkte ik dat de letters op de tandwielen te klein waren om te printen en de binnendiameter te stroef om te bewegen. Daarom heb ik versie 2 gemaakt waarbij de tandwielen over de as heen gaan zodat er grotere tekst op kan en ze beter kunnen draaien.&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.amazonaws.com%2Fuploads%2Farticles%2F05wap44s6667mcsoeln6.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.amazonaws.com%2Fuploads%2Farticles%2F05wap44s6667mcsoeln6.png" alt=" " width="800" height="529"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ook heb ik ervoor gekozen om versie 2 25% groter te maken omdat de printer op dit formaat erg lastig precies kan printen wat problemen kan veroorzaken. Na nog wat extra aanpassingen en finetunen is er een resultaat uitgekomen wat makkelijk draait goed vastzit en niet snel kapot gaat.&lt;/p&gt;

&lt;h3&gt;
  
  
  Eindresultaat
&lt;/h3&gt;

&lt;p&gt;Na het maken van versie 3 waarin ik in de tandwielen een overhang had gemaakt zodat de printer zonder supports kon printen en dit helemaal niet werkte ben ik teruggegaan naar versie 2. Ik kwam er namelijk achter dat het stroef draaien van versie 2 verholpen werd na een paar minuten van ronddraaien.&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.amazonaws.com%2Fuploads%2Farticles%2Fduls6oc8wqapi1g9ytus.jpeg" 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.amazonaws.com%2Fuploads%2Farticles%2Fduls6oc8wqapi1g9ytus.jpeg" alt=" " width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>hobby</category>
      <category>design</category>
      <category>3dprinting</category>
    </item>
    <item>
      <title>Afstandsbediening houders</title>
      <dc:creator>Daniël R</dc:creator>
      <pubDate>Tue, 21 Oct 2025 12:54:59 +0000</pubDate>
      <link>https://dev.to/danil_r_0913f2ae76f4f04d/afstandsbediening-houders-3o33</link>
      <guid>https://dev.to/danil_r_0913f2ae76f4f04d/afstandsbediening-houders-3o33</guid>
      <description>&lt;p&gt;Een probleem waar ik al langere tijd tegenaan loop is dat mijn kamer niet groot genoeg is maar ook niet goed genoeg is ingedeeld voor een nachtkastje. Dat betekend dat er naast mijn bed op de grond altijd een aantal spullen liggen zoals telefoons, opladers en afstandsbedieningen. Vooral de laatste de afstandsbedieningen erger ik me al een tijdje aan. Toen bedacht ik me dat ik toegang heb tot een 3d-printer en designsoftware dus het probleem hartstikke goed zelf kan oplossen. Het gaat over de volgende twee afstandsbedieningen.&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.amazonaws.com%2Fuploads%2Farticles%2F3ecufnp0fq4h12s6irp3.jpg" 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.amazonaws.com%2Fuploads%2Farticles%2F3ecufnp0fq4h12s6irp3.jpg" alt=" " width="800" height="624"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Er zijn een paar belangrijke eisen waaraan het design moet voldoen&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Ze moeten in de muur naast me bed geschroefd kunnen worden&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;De afstandsbedieningen moeten er stevig inzitten&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;De afstandsbedieningen moeten er makkelijk in en uit te halen zijn&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;De houders mogen niet te lelijk zijn en niet teveel uitsteken&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Na een korte tijd ontwerpen zijn daar deze twee ontwerpen uitgekomen elegant en simpel. De houders zijn beide voorzien van twee gaten voor schroeven zodat ze opgehangen kunnen worden en kunnen makkelijk geprint worden.&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.amazonaws.com%2Fuploads%2Farticles%2Fnonlx34otzsmnyll4prn.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.amazonaws.com%2Fuploads%2Farticles%2Fnonlx34otzsmnyll4prn.png" alt=" " width="800" height="447"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Na de eerste print werkte de LED afstandsbediening houder perfect. De houder voor de TV afstandsbediening werkte nog wat minder de 2 lipjes aan de voorkant zorgde ervoor dat die er moeilijk in en uitging omdat je hem er niet in kon schuiven zoals bij de andere houder. om dit op te lossen moeten deze lipjes kleiner om te testen hoe klein heb ik het eerste prototype afgeschuurd tot die wel goed werkt. Ook kwam ik erachter dat die veel kleiner kon en dan alsnog goed zou werken dus heb ik dat ook gedaan.&lt;/p&gt;

&lt;h3&gt;
  
  
  Eindresultaat
&lt;/h3&gt;

&lt;p&gt;Al is dit een van de makkelijkere projecten is het wel een van mijn beste hierdoor ligt er namelijk minder troep om de grond en het ziet er nog eens netjes uit ook.&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.amazonaws.com%2Fuploads%2Farticles%2F7xiofpd371ypg4s24yrm.jpg" 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.amazonaws.com%2Fuploads%2Farticles%2F7xiofpd371ypg4s24yrm.jpg" alt=" " width="800" height="561"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>hobby</category>
      <category>design</category>
    </item>
  </channel>
</rss>
