<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Rtsp on ポンコツ地方エンジニアの技術ブログ</title><link>https://blog-0847c6.gitlab.io/tags/rtsp/</link><description>Recent content in Rtsp on ポンコツ地方エンジニアの技術ブログ</description><generator>Hugo -- gohugo.io</generator><language>ja-jp</language><lastBuildDate>Tue, 03 Aug 2021 00:00:00 +0900</lastBuildDate><atom:link href="https://blog-0847c6.gitlab.io/tags/rtsp/index.xml" rel="self" type="application/rss+xml"/><item><title>[python] ネットワークカメラの画像を RTSP で取得して表示・保存</title><link>https://blog-0847c6.gitlab.io/posts/2021/08/03/python/</link><pubDate>Tue, 03 Aug 2021 00:00:00 +0900</pubDate><guid>https://blog-0847c6.gitlab.io/posts/2021/08/03/python/</guid><description>&lt;p&gt;やり方はいろいろあると思いますが、OpenCV を使えば簡単にできました。&lt;/p&gt;
&lt;h2 id="画像を取得して表示"&gt;&lt;a href="#%e7%94%bb%e5%83%8f%e3%82%92%e5%8f%96%e5%be%97%e3%81%97%e3%81%a6%e8%a1%a8%e7%a4%ba" class="header-anchor"&gt;&lt;/a&gt;画像を取得して表示
&lt;/h2&gt;&lt;p&gt;&lt;code&gt;VideoCapture&lt;/code&gt; の引数に RTSP の URL を記述するだけで簡単に画像を取得できます。&lt;br&gt;
URL はネットワークカメラの仕様を確認してください。&lt;br&gt;
今回は Panasonic のカメラを使いました。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;cv2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;user_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;admin&amp;#34;&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;user_pw&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;password&amp;#34;&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;host&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;192.168.0.1&amp;#34;&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&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="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;VideoCapture&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;rtsp://&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;user_pw&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;@&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/MediaInput/h264&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;ret&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;frame&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cap&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;ret&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;cv2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;imshow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;VIDEO&amp;#39;&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&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;cv2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;waitKey&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&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="ne"&gt;KeyboardInterrupt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;KeyboardInterrupt&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;break&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;cap&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;release&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;cv2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;destroyAllWindows&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;VideoCapture の引数を変更すれば、USB カメラや動画ファイルの読み込み、連番のJPGファイルも一括で読み込めたりするので便利です。&lt;/p&gt;
&lt;h2 id="保存"&gt;&lt;a href="#%e4%bf%9d%e5%ad%98" class="header-anchor"&gt;&lt;/a&gt;保存
&lt;/h2&gt;&lt;p&gt;今回 RTSP では H.264 で取得しましたが、フレームの処理は OpenCV 側で上手く処理してくれているので、キーフレームとか GOP とか何も考えずに保存できます。&lt;/p&gt;
&lt;h3 id="jpg-の保存"&gt;&lt;a href="#jpg-%e3%81%ae%e4%bf%9d%e5%ad%98" class="header-anchor"&gt;&lt;/a&gt;JPG の保存
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cv2.imwrite(&amp;#34;sample.jpg&amp;#34;, frame)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="動画の保存"&gt;&lt;a href="#%e5%8b%95%e7%94%bb%e3%81%ae%e4%bf%9d%e5%ad%98" class="header-anchor"&gt;&lt;/a&gt;動画の保存
&lt;/h3&gt;&lt;p&gt;&lt;code&gt;VideoWriter_fourcc&lt;/code&gt; でコーデックを指定します。&lt;br&gt;
以下が参考になりました。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://qiita.com/Gyutan/items/e279e8680b90ca891250" target="_blank" rel="noopener"
 &gt;https://qiita.com/Gyutan/items/e279e8680b90ca891250&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;画像サイズはキャプチャから取得できる値をそのまま保存時にも使っていますが、フレームレートは取得できないので、直接指定しています。&lt;br&gt;
これが合っていないと当然おかしなことになります（早送り再生やスロー再生したような状態になります）。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;import cv2
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;user_id = &amp;#34;admin&amp;#34; 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;user_pw = &amp;#34;password&amp;#34; 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;host = &amp;#34;192.168.0.1&amp;#34; 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cap = cv2.VideoCapture(f&amp;#34;rtsp://{user_id}:{user_pw}@{host}/MediaInput/h264&amp;#34;)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;width = cap.get(cv2.CAP_PROP_FRAME_WIDTH)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;height = cap.get(cv2.CAP_PROP_FRAME_HEIGHT)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;fmt = cv2.VideoWriter_fourcc(*&amp;#39;MP4V&amp;#39;)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;frame_rate = 30.0
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;writer = cv2.VideoWriter(&amp;#34;sample.mp4&amp;#34;, fmt, frame_rate, (int(width), int(height)))
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;while(True):
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; try:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ret, frame = cap.read()
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; if ret == True:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; writer.write(frame)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; cv2.imshow(&amp;#39;VIDEO&amp;#39;, frame)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; cv2.waitKey(1)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; except KeyboardInterrupt:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; print(&amp;#34;KeyboardInterrupt&amp;#34;)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; break
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;writer.release()
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cap.release()
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cv2.destroyAllWindows()
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="参考-url"&gt;&lt;a href="#%e5%8f%82%e8%80%83-url" class="header-anchor"&gt;&lt;/a&gt;参考 URL
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://qiita.com/gao_gao/items/3b5485695b464aa789df" target="_blank" rel="noopener"
 &gt;https://qiita.com/gao_gao/items/3b5485695b464aa789df&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://rikoubou.hatenablog.com/entry/2019/01/15/174751" target="_blank" rel="noopener"
 &gt;https://rikoubou.hatenablog.com/entry/2019/01/15/174751&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://qiita.com/Gyutan/items/e279e8680b90ca891250" target="_blank" rel="noopener"
 &gt;https://qiita.com/Gyutan/items/e279e8680b90ca891250&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item></channel></rss>