min117の日記

初期desireもち。趣味Mac,メインFedora,仕事xp。

WSL2ではデフォルトでプライベートIPが有効らしい

ハピタス登録で1,000円分になるURL

その買うを、もっとハッピーに。|ハピタス

 

WSL2にて

なんぞこれ。

家のネットワークは192.168...体系だし、このWSL2は無線LANのWin10(eth0なんて使ってない)んだけど。

 

WSL2からはプライベートIPアドレスが有効になっているらしい。

rcmdnk.com

うざいな。

 

コレ仮にWSL2上にPHPのサーバ立てて、例えばiMacからアクセスした場合とか、Windows10内部でForwardingというか、ポート変換してやんなきゃいけない理屈。

 

めんどいのう。たぶんUbuntu側だけプライベートIP(172.22.xxx.xxx)なのをやめて、Windows側で持っているIP(192.168.xxx.xxx)をそのままUbuntu側に透過するような設定があるはず。

 

探す。

 

 

 

その買うを、もっとハッピーに。|ハピタス

RaspberryPi3 WebカメラでQRコードを読み取る(イベント会場QR受付システムの準備)

ハピタス登録で1,000円分になるURL

その買うを、もっとハッピーに。|ハピタス

 

ラズパイでQRコードを読む

これやりたい。

hellobreak.net

カメラはメルカリでGETした。

 

$ sudo apt install libavutil56 libcairo-gobject2 libgtk-3-0 libqtgui4 libpango-1.0-0 libqtcore4 libavcodec58 libcairo2 libswscale5 libtiff5 libqt4-test libatk1.0-0 libavformat58 libgdk-pixbuf2.0-0 libilmbase23 libjasper1 libopenexr23 libpangocairo-1.0-0 libwebp6

$ sudo pip3 install opencv-python

やたら時間かかる。opencvはやっぱ重いのか→なぜか固まった。待てなくて電源ブチで再起動。やり直す。

今度は負荷計測しながらやる。Load averageはそんなでもないが…

16分経過したところでCPU使用率が4コア全部100%近くになった。

ハングしてるよなこれ。

VNCして直接pi上でやってみるか。

この「Running setup.py bdist_wheel for...」で固まるんだよな。

負荷はそれほどではないぽいが。VNCもちゃんと動いてるし…しかしインストールが進まない。

 

そもそもbdist_wheelって何よ

blog.n-t.jp

うーん、わからん。

 

そうか。apt update してないから?いったんキャンセルして(sudo apt updateしてから)やり直す。

$ sudo apt upgrade

$ sudo apt update

upgradeが大量にある。これか原因は。

upgrade後に再度opencvのインストール。

$ sudo pip3 install opencv-python

やはり固まった?かと思うくらい時間かかった(sshも通じない、pingだけは通る)状態が続いたが、まる1日放っておいたらコンソールが返ってきた。

 

しかし、python3上げてimport cv2してもNo module named 'cv2'エラーになってしまう

バージョン指定でopencvをインストールし直してみる

$ sudo pip3 install opencv-python==4.1.0

$ sudo pip3 install opencv-python==4.6.0.66

あれ!?数分でインストール成功した!

 

最新バージョン(4.7.0.68)がバグってだだけか!一個前の(4.6.0.66)でインストールできたっぽい!

と思ったが…

$ python3

>>> import cv2

またimport cv2がエラーに。

ImportError: libcblas.so.3 で調べる。

こうかな。

$ sudo apt-get install libatlas-base-dev

$ python3

>>> import cv2

またエラーか…が、まだまだ諦めない。

ImportError: numpy.core.multiarray でググる

時間かかる…結局またbdist_wheelか…しかし今回はsshは固まらないので進んでるっぽい。

Webにも似たような経験談

 

htopでモニタリングしたら負荷が凄いことに。

$ htop

Load averageが20超えてる。こりゃ固まって見えるわけだ…(かろうじて数分に1回画面が更新されるのでhtop自体は生きてる。numpyのインストールが重すぎるだけか)

 

…(gccに丸2日かかった…)

$ python3

>>> import cv2

まだダメ…だと…

 

numpyのバージョンチェック。

$ python3

>>> import numpy as np

>>> print(np.__version__)

>>> print(np.__path__)

ふむ。

 

ここで発想を変えてみよう。既にコンパイル済みのopencv2のバイナリがあればいいのではないか。

これか。

今のOSバージョンはbusterなんだが…Bullseyeって何…

いいや。OSの違いは無視。入れてみる。ままよ。

$ wget https://github.com/prepkg/opencv-raspberrypi/releases/latest/download/opencv.deb

ダメね。

そうか、コンパイル済みのopencvやnumpy取ってきても意味ないのか。要はインストールされてるpython3にマッチしたopencv&numpyを組み上げなきゃいけないんだから、やっぱpip3 numpy --upgradeしてnumpyのコンパイル走らせる必要があるのかも。

 

エラーをもっかいよく見てみる

これか。

$ sudo pip install numpy --upgrade --ignore-installed

いったんキャンセル。

 今のnumpy 1.16.2

 入るnumpy 1.16.6

状況は分かった。

 

再開。

$ sudo pip3 install numpy --upgrade --ignore-installed

あれ?pip3だと

 今のnumpy 1.16.2

 入るnumpy 1.21.6

になる。なんかpipかpip3かでnumpyが違う。このへんが原因なのか?

 

qiita.com

www.koi.mashykom.com

 

 

 

 

 

その買うを、もっとハッピーに。|ハピタス

 

RaspberryPi4 のproxy経由のテレビ視聴が実用的すぎて便利

ハピタス登録で1,000円分になるURL

その買うを、もっとハッピーに。|ハピタス

 

全国どこでもTV

首都圏にある社宅内のKTV-FSUSBで受信したtsを

ド田舎にあるpi4に(VPN経由で)飛ばして

 それをnginxのproxyサーバで反射したのを

wireguard(VPN)に配信して観る、と。

 

こうなる。

 

 

超便利やな。

ま、テレビなんて今やほとんど見る価値ないから、たまーに覗くくらいだけど。

min117.hatenablog.com

 

min117.hatenablog.com



WSL→bash上のpython3でOpenCVでカメラ画像を取り込めるかテスト→NG

ハピタス登録で1,000円分になるURL

その買うを、もっとハッピーに。|ハピタス

 

WSL(Windows Subsystem for Linux)つまりはコマンドプロンプトで動くLinux的な環境から、Windowsに接続したWebカメラを使いたい。

以下、cmd=Windowsコマンドプロンプト、wt=WindowsTerminal。

cmd> wt

wt> sudo apt install python3-pip

expy-style.net

 

wt> pip install opencv-python

 

wt>pip install pyzbar


WSLでUSBのWebカメラを使う設定

zenn.dev

 

管理者でWindowsTerminalを上げ直す

管理者wt> wsl --update

管理者wt> wsl --status

管理者wt> winget install --interactive --exact dorssel.usbipd-win

インストールできたかに見えるが。

 

とりあえず apt-get update流す

管理者wt> sudo apt-get update

 

linux-toolsなるものを入れる。

管理者wt> sudo apt install -y linux-tools-5.4.0-77-generic hwdata

管理者wt> sudo update-alternatives --install /usr/local/bin/usbip usbip /usr/lib/linux-tools/5.4.0-77-generic/usbip 20

 

管理者wt> usbipd wsl list

管理者wt> sudo apt install -y linux-tools-4.4.0-19041-Microsoft

管理者wt> apt search linux-tools | tee -a my_apt-search.txt

カーネル4.4.0対応のパッケージらしきもの目視できず。

 

ち。

カーネル4.4.0てのがダメらしい。記事のとおり5.4.0に上げるしかないか。

Ubuntu20.04はそのままでカーネルUpdateする方法探す。

 

learn.microsoft.com

 

 

どうもあれやな、WSL自体のカーネルは5に上がってるけど、その上に乗っかってるUbuntuカーネルが4のまま、って状態になってるぽい。

 

あれ、カメラ認識されるようになったぞ?

cmd> usbipd wsl list

 

cmd> usbipd wsl attach --busid 2-2

ダメか。wsl1じゃダメで、wsl2にアプデが必要らしい。

loumo.jp

cmd> wsl -l -v

learn.microsoft.com

 

PowerShellでHyperVを有効化するらしいコマンドを叩く。再起動求められる。

PS> dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart

 

念のためGUIHyper-Vサポートも有効化する。

インストール前はこうだったのが…

インストール後はこうなる。仮想化うんぬんのエラーが消えている。

管理者wt> wsl --set-default-version 2

 

もう一度カメラを(Windows側からUbuntu側へ)アタッチしてみる。

いやいや、なんでWSL2になってないエラーが出るのよ。WSL2にしたじゃん…

再起動してみるか。

learn.microsoft.com

 

cmd> wsl -l -v

したときに、Ubuntu-20.04のVERSIONが1になっちゃってる。これがWSL1だという意味なのか?としたらUbuntuをアンインストールして入れ直してみるか。

いったん再起動。

www.kkaneko.jp

Ubuntu-22.04のVERSIONが2(つまりWSL2)に上がっている!

管理者wt> sudo apt-get -y update

管理者wt> sudo apt install linux-tools-virtual hwdata

(これがエラーになるときは sudo apt-get -y updateを忘れている)

管理者wt> sudo update-alternatives --install /usr/local/bin/usbip usbip `ls /usr/lib/linux-tools/*/usbip | tail -n1` 20

管理者wt> winget install --interactive --exact dorssel.usbipd-win

おっっっっしゃ!USBカメラのアタッチ(Windows側からUbuntu22.04側へ)できた!

あとはWSL2のPythonからこれを扱えるかやってみる。

 

rootのパスワード忘れてsu-できないだと…Ubuntu22.04入れなおした。

もう一回繰り返す。碇ゲンドウばりに(成功するまで)何度でもやる。

管理者wt> sudo apt-get -y update

管理者wt> sudo apt install linux-tools-virtual hwdata

(これがエラーになるときは sudo apt-get -y updateを忘れている)

管理者wt> sudo update-alternatives --install /usr/local/bin/usbip usbip `ls /usr/lib/linux-tools/*/usbip | tail -n1` 20

 

もっかいカメラをアタッチして(bash上げてないとアタッチできない!

次はPython

管理者wt> sudo apt-install python3-pip

管理者wt> pip install opencv-python

管理者wt> pip install pyzbar

いよいよ未知の領域

zenn.dev

Windows側からの認識の確認は

cmd> usbipd wsl list

Ubuntu側からの認識の確認は

管理者wt> lsusb

おっしゃlsusbでも認識してる!

 

/dev/video*に認識されてるかな?

管理者wt> ls -l /dev/video*

ダメじゃん…なぜ。いいや無視。pythonで見えるか確かめる。

 

wt> python3

>>> import cv2

ぐぬぬ

cocoinit23.com

管理者wt> sudo apt-get install libgl1-mesa-dev

import cv2できた!

testコードは丸写し

import cv2

W=640
H=480
cap = cv2.VideoCapture(0)
cap.set(cv2.CAP_PROP_FOURCC, cv2.VideoWriter_fourcc('M','J','P','G'))
#cap.set(cv2.CAP_PROP_FOURCC, cv2.VideoWriter_fourcc('Y','U','Y','V'))
cap.set(cv2.CAP_PROP_FRAME_WIDTH, W)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, H)
cap.set(cv2.CAP_PROP_FPS, 30)

while True:
    ret, frame = cap.read()
    if not ret:
        continue
    cv2.imshow('usb cam test', frame)
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

cap.release()
cv2.destroyAllWindows()

ぐはっ!なんでだ!たぶん/dev/video0が無いからか!

続く

 

 

 

 

 

その買うを、もっとハッピーに。|ハピタス

Prime Video「finding carter」を見たいのでMTVを無料14日間だけ体験する

ハピタス登録で1,000円分になるURL

その買うを、もっとハッピーに。|ハピタス

 

久々に面白そうなの

これは続き見たい。

 

www.youtube.com


MTVを契約で視聴できるらしい。月額330円か。

見たいのだけみたら解約する。

jp.amazonforum.com

 

 

 

 

その買うを、もっとハッピーに。|ハピタス

ChatCPT「テニスラケットのガットの張りをメモして管理するWebアプリのサンプルコードを示して」

ハピタス登録で1,000円分になるURL

その買うを、もっとハッピーに。|ハピタス

 

Ruby on Railsアプリ

ほんとに動くか近いうちに試す。

 

# In the controller
class RacketController < ApplicationController
  def index
    @rackets = Racket.all
  end

  def new
    @racket = Racket.new
  end

  def create
    @racket = Racket.new(racket_params)
    if @racket.save
      redirect_to rackets_path
    else
      render :new
    end
  end

  private

  def racket_params
    params.require(:racket).permit(:name, :tension)
  end
end

# In the model
class Racket < ApplicationRecord
  validates :name, presence: true
  validates :tension, numericality: { greater_than: 0 }
end

# In the view (new.html.erb)
<h1>New Racket</h1>
<%= form_for @racket do |f| %>
  <% if @racket.errors.any? %>
    <div class="error_messages">
      <h2>Form is invalid</h2>
      <ul>
        <% @racket.errors.full_messages.each do |message| %>
          <li><%= message %></li>
        <% end %>
      </ul>
    </div>
  <% end %>
  <p>
    <%= f.label :name %><br>
    <%= f.text_field :name %>
  </p>
  <p>
    <%= f.label :tension %><br>
    <%= f.number_field :tension %>
  </p>
  <p>
    <%= f.submit %>
  </p>
<% end %>

# In the view (index.html.erb)
<h1>Listing Rackets</h1>
<table>
  <thead>
    <tr>
      <th>Name</th>
      <th>Tension</th>
    </tr>
  </thead>
  <tbody>
    <% @rackets.each do |racket| %>
      <tr>
        <td><%= racket.name %></td>
        <td><%= racket.tension %></td>
      </tr>
    <% end %>
  </tbody>
</table>

 

 

 

 

その買うを、もっとハッピーに。|ハピタス

ChatGPT「PHPで書かれたファイルアップロードのコードを示して」

ハピタス登録で1,000円分になるURL

その買うを、もっとハッピーに。|ハピタス

 

ChatGPT完璧

すげえ

PHPで書かれたファイルアップロードのコードを示して」

<form action="upload.php" method="post" enctype="multipart/form-data">
  Select file to upload:
  <input type="file" name="fileToUpload" id="fileToUpload">
  <input type="submit" value="Upload File" name="submit">
</form>

 

<?php
if(isset($_POST['submit'])) {
  $target_dir = "uploads/";
  $target_file = $target_dir . basename($_FILES["fileToUpload"]["name"]);
  $uploadOk = 1;
  $imageFileType = strtolower(pathinfo($target_file,PATHINFO_EXTENSION));
  
  if (move_uploaded_file($_FILES["fileToUpload"]["tmp_name"], $target_file)) {
      echo "The file ". basename( $_FILES["fileToUpload"]["name"]). " has been uploaded.";
  } else {
      echo "Sorry, there was an error uploading your file.";
  }
}
?>

 

複数ファイルupload対応PHP

ちゃんとfor文はさみよる。すっげえ。

PHPで書かれた複数ファイルアップロードのコードを示して」

<?php

$server_url = "http://example.com/upload.php";

if (isset($_FILES['files'])) {
    $errors = ;
    $files = $_FILES['files'];

    for ($i = 0; $i < count($files['name']); $i++) {
        $file_name = $files['name'][$i];
        $file_tmp = $files['tmp_name'][$i];
        $file_type = $files['type'][$i];
        $file_size = $files['size'][$i];
        
        if ($file_size > 2097152) {
            $errors = 'File size must be less than 2 MB';
        }

        if (empty($errors)) {
            $post_data = array(
                'file_contents' => base64_encode(file_get_contents($file_tmp)),
                'file_name' => $file_name,
                'file_type' => $file_type,
            );

            $ch = curl_init();
            curl_setopt($ch, CURLOPT_URL, $server_url);
            curl_setopt($ch, CURLOPT_POST, 1);
            curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

            $response = curl_exec($ch);
            curl_close($ch);

            if ($response === 'Success') {
                echo "File '$file_name' uploaded successfully<br>";
            } else {
                echo "Failed to upload file '$file_name'<br>";
            }
        } else {
            foreach ($errors as $error) {
                echo $error . "<br>";
            }
        }
    }
}

?>
<form action="" method="post" enctype="multipart/form-data">
    <input type="file" name="files" multiple>
    <input type="submit" value="Upload">
</form>

 

Ruby on Railsだとどうか

完璧

# In the controller
def create
  params[:files].each do |file|
    @upload = Upload.create(file: file)
  end
  redirect_to uploads_path
end

# In the model
class Upload < ApplicationRecord
  mount_uploader :file, FileUploader
end

# In the uploader
class FileUploader < CarrierWave::Uploader::Base
  storage :file
end

# In the view
<%= form_for @upload, url: uploads_path, html: { multipart: true } do |f| %>
  <%= file_field_tag "files", multiple: true %>
  <%= f.submit "Upload" %>
<% end %>

 

Pythonでやってみる

pythonで書かれた複数ファイルアップロードのコードを示して」

import requests

def upload_files(url, files):
    for file in files:
        with open(file, 'rb') as f:
            response = requests.post(url, files={file: f})
            if response.status_code == 200:
                print(f'File {file} was successfully uploaded.')
            else:
                print(f'File {file} was not uploaded. Response code: {response.status_code}')

files = ['file1.txt', 'file2.txt']
upload_files('http://example.com/upload', files)

 

Javaでやってみる

「javaで書かれたファイルアップロードのコードを示して」



import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;

public class FileUpload {
  public static void uploadFile(String serverURL, File file) {
    try {
      String boundary = Long.toHexString(System.currentTimeMillis());
      String CRLF = "\r\n";

      URL url = new URL(serverURL);
      URLConnection connection = url.openConnection();
      HttpURLConnection httpConnection = (HttpURLConnection) connection;
      httpConnection.setUseCaches(false);
      httpConnection.setDoOutput(true);
      httpConnection.setRequestMethod("POST");
      httpConnection.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);

      try (OutputStream output = httpConnection.getOutputStream();
           InputStream input = new FileInputStream(file)) {
        output.write*1;
        output.write*2;
        output.write*3;
        output.write(CRLF.getBytes());

        byte buffer = new byte[4096];
        int bytesRead;
        while ((bytesRead = input.read(buffer)) != -1) {
          output.write(buffer, 0, bytesRead);
        }

        output.write((CRLF + "--" + boundary + "--" + CRLF).getBytes());
        output.flush();
      }

      int responseCode = httpConnection.getResponseCode();
      if (responseCode != HttpURLConnection.HTTP_OK) {
        throw new IOException("Server returned non-OK status: " + responseCode);
      }
    } catch (IOException e) {
      e.printStackTrace();
    }
  }
}

 

複数ファイルupload対応java

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.List;

public class FileUpload {
  public static void uploadFiles(String serverURL, List<File> files) {
    try {
      String boundary = Long.toHexString(System.currentTimeMillis());
      String CRLF = "\r\n";

      URL url = new URL(serverURL);
      HttpURLConnection connection = (HttpURLConnection) url.openConnection();
      connection.setRequestMethod("POST");
      connection.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);
      connection.setDoOutput(true);

      try (OutputStream output = connection.getOutputStream()) {
        for (File file : files) {
          output.write(("--" + boundary + CRLF).getBytes());
          output.write(("Content-Disposition: form-data; name=\"file\"; filename=\"" + file.getName() + "\"" + CRLF).getBytes());
          output.write(("Content-Type: application/octet-stream" + CRLF + CRLF).getBytes());

          try (InputStream input = file) {
            byte buffer = new byte[1024];
            for (int length = 0; (length = input.read(buffer)) > 0;) {
              output.write(buffer, 0, length);
            }
            output.write(CRLF.getBytes());
          }
        }
        output.write*4;
      }

      if (connection.getResponseCode() == HttpURLConnection.HTTP_OK) {
        System.out.println("Files uploaded successfully");
      } else {
        System.out.println("File upload failed");
      }
    } catch (IOException e) {
      System.out.println("File upload failed: " + e.getMessage());
    }
  }

  public static void main(String[] args) {
    List<File> files = new ArrayList<>();
    files.add(new File("file1.txt"));
    files.add(new File("file2.txt"));

    uploadFiles("http://example.com/upload", files);
  }
}

 

 

 

 

 

その買うを、もっとハッピーに。|ハピタス

*1:"--" + boundary + CRLF).getBytes(

*2:"Content-Disposition: form-data; name=\"file\"; filename=\"" + file.getName() + "\"" + CRLF).getBytes(

*3:"Content-Type: application/octet-stream" + CRLF).getBytes(

*4:"--" + boundary + "--" + CRLF).getBytes(