ボタン操作で別ブラウザを開く

ボタンをクリックすると別の画面が開くという機能を実装しました.

参考は以下です.

www.javadrive.jp

 

これを別で.tsファイルを作成し,実装してみました.

まず,.htmlファイルは以下になります.


<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>サンプル</title>
</head>
<body>

  <p>サンプルページです。</p>

  <input type="button" value="button1" id="mybtn1"> // src="./assets/img/CameraIcon.png"を入れると,ボタンを好きな見た目に変えれます
</body>

次に新規に.tsファイルを作成し,以下をコピペします.


export const mybtn1: HTMLElement       = document.getElementById("mybtn1")  as HTMLElement;
// ユーザカメラのアイコンクリック時の処理
mybtn1.addEventListener('click', () => { // width=300,height=300,left=0,top=0
  let option = 'width=1000,height=1000,left=0,top=0'
	open('./src/html/〇〇.html','mywindow', option);
});

別画面のキャプチャを表示する方法

以下サイトがわかりやすいです.

qiita.com

 

もし,上記サイトが停止していた場合にいかにコードだけ記述しておきます.

解説は上記サイトをご覧ください.


<html>

<head>
    <meta charset="UTF-8">
    <title>test
</head>

<body>
    <p>This example shows you the contents of the selected part of your display.
        Click the Start Capture button to begin.</p>
    <p><button id="start">Start Capture</button> 
    <button id="stop">Stop Capture</button></p>
    <video id="video" autoplay></video>
    <br>
</body>
<script>
    const videoElem = document.getElementById("video");
    const startElem = document.getElementById("start");
    const stopElem = document.getElementById("stop");

    // Options for getDisplayMedia()
    var displayMediaOptions = {
        video: {
            cursor: "always"
        },
        audio: false
    };

    // Set event listeners for the start and stop buttons
    startElem.addEventListener("click", function (evt) {
        startCapture();
    }, false);

    stopElem.addEventListener("click", function (evt) {
        stopCapture();
    }, false);

    async function startCapture() {
        try {
            videoElem.srcObject = await navigator.mediaDevices.getDisplayMedia(displayMediaOptions);
        } catch (err) {
            console.error("Error: " + err);
        }
    }

    function stopCapture(evt) {
        let tracks = videoElem.srcObject.getTracks();

        tracks.forEach(track => track.stop());
        videoElem.srcObject = null;
    }
</script>

</html>

Pupil-Detectionを使用してみる

以下のリポジトリを使用しました.

github.com

 

こちらをローカルにクローンしたのちに

Anaconda Navigator で


    python 3.9
    conda install opencv
    conda install numpy

と環境を作成したのちに,ひとまず,pupil_detect_imagesの方を実行してみると,cv2.contourAreaの部分でエラーが起きました. この対処法に関しては,以下のサイトを参考にしてください.

teratail.com

原因としては,contourArea(x)に入力するfindContoursに問題があったようです.

以下を見てください.


    OpenCVのv3系
    im2,contours,hierarchy = cv.findContours(thresh, 1, 2)
    OpenCVのv4系
    contours,hierarchy = cv.findContours(thresh, 1, 2)

インストールする際にただ単にconda install opencvとしてしまっていたことが原因で,自動的に最新版のv4系をインストールしていました. そのため,戻り値を[1]ではなく,[0]にしてあげると適切なcontoursを取得することができ,実行ができるようになりました.

Vuetify 3でページングを実装する

公式HPにある以下を使用して、実装していきます。

 

vuetifyjs.com

 

Vuetify 3を使用できる状態であることが前提とします。

まだできていない方は以下を参考にしてプロジェクトを作成してみてください。

challenge-think.hatenablog.com

 

まず、以下をページネーションを作成したい場所にコピペします。


    h1>タイトル</h1>
    <v-table density="conpact">
      <thead>
        <tr>
          <th width=10px class="text-left">
            <div  class="d-flex flex-wrap flex-row">
              Date
              <div style="margin: 0% 0% 0% 10%; color: gray;">
                <v-chip
                  density="compact"
                  @click="changeOrder()"
                  v-bind:text="orderType"
                ></v-chip>
              </div>
            </div>
          </th>
          <th class="text-left">
            Title
          </th>
        </tr>
      </thead>
      <tbody>
        <tr
          v-for="newsInfo in pageList[page-1]"
          :key="newsInfo.title"
        >
          <td>{{ newsInfo.date }}</td>
          <td v-html="newsInfo.title"></td>
        </tr>
      </tbody>
    </v-table>
    <div class="text-center">
      <v-pagination
        v-model="page"
        v-bind:length="totalPages"
        :total-visible="6"
        density=conpact
      ></v-pagination>
    </div>

次に、同じ.vueファイルのscriptに以下をコピペします。


    import { ref, computed, reactive} from 'vue'; 
  import NewsInfoList_RAW from '@/assets/data/NewsData';
  
  const page = ref(1);

  /* ブログをソートする */
  const daySort = (a,b) => {
    const [ a_year, a_month, a_day ] = a.date.split('.');
    const [ b_year, b_month, b_day ] = b.date.split('.');

    if(a_year !== b_year){
      return a_year - b_year;
    }else if(a_month !== b_month){
      return a_month - b_month;
    }else if(a_day !== b_day){
      return a_day - b_day;
    }
  }
  var NewsInfoList = NewsInfoList_RAW.sort((a,b) => daySort(b, a));
  const orderType = ref("↓");

  // 1ページあたりの記事数
  const parPage = 10;

  /* 総ページ数を数える */
  var syou = (NewsInfoList.length)/parPage;
  var totalPages;
  if(syou%1 === 0){
    totalPages = Math.floor(syou);
  }else{
    totalPages = Math.floor(syou)+1;
  }

  var pageList = reactive([]);
  var newsCount;
  /* ページごとにブログを分割する */
  const createPageList = (NewsInfoList) => {
    pageList.splice(0); // 配列を空にする
    newsCount = 0;
    for(let i=0; i<totalPages; i++){
      pageList[i]=[];
      for(let j=0;j<parPage;j++){
        if(newsCount<NewsInfoList.length){
          pageList[i][j] = NewsInfoList[newsCount++];
        }
      }
    }
  }
  /* ページ毎にブログを格納する */
  createPageList(NewsInfoList);

  /* 昇順・降順変更 */
  const changeOrder = () => {
    if(orderType.value === "↑"){
      orderType.value = "↓";
      NewsInfoList = NewsInfoList_RAW.sort((a,b) => daySort(b, a));
    }else{
      orderType.value = "↑";
      NewsInfoList = NewsInfoList_RAW.sort((a,b) => daySort(a, b));
    }
    /* ページ毎にブログを格納する */
    createPageList(NewsInfoList);
  }

最後にimportしてくる元々のデータを作成します。 新しく.jsファイルを作成し、以下をコピペしてください。 ※上記のscriptの部分でimportしているので、パスを正確に書き換えてください。


    const NewsInfoList_RAW = [
  {
    type : "hoby", 
    date : "2023.04.09",
    title: `<a href="https://challenge-think.hatenablog.com/" target="_blank">Webサイト</a>をリニューアルしました`,
  },
]

export default NewsInfoList_RAW;

ただ、ここで、export defaultは余り推奨されないようです。

engineering.linecorp.com

OpenCVで瞬き検出を行う

やりたいこと

USBカメラでリアルタイムで取得している映像から瞬きを検出するプログラムを書いてみます。

以下のサイトを見ながら実装しました。

youtu.be

 

使用するもの

  • Anaconda
  • VSCode
  • USB カメラ(内臓でも可能)

環境構築

anaconda navigatorを開き、「create」から新規環境を作成します。

pythonのバージョンは3.9.0ですることにします。

環境が完成したら、緑色の三角ボタンを押してTerminalを開きます。

Terminalで以下を打ち込んでください。

$ pip install mediapipe

$ pip install cvzone

それでは、この環境を使って書いていきましょう。

実装

新規ディレクトリを作成し、VSCodeを開きます。

ディレクトリの中で、git bashを開いてcode .と打ち込むと開くことができます。

まずは、先ほど構築した環境を使う設定をしましょう。

右下の〇.〇〇.〇〇-bitと書かれているところをクリックします。その後、画面上に今までに作成した環境リストが出てくるので、そこから先ほど作成した環境を選びます。

 

次に、新規ファイル(Python)を作成します。

※ここで、コードの中身よりまずは実装したいという方は以下をコピペして実行してみてください。

while True:

    if cap.get(cv2.CAP_PROP_POS_FRAMES) == cap.get(cv2.CAP_PROP_FRAME_COUNT):
        cap.set(cv2.CAP_PROP_POS_FRAMES, 0)

    success, img = cap.read()
    img, faces = detector.findFaceMesh(img, draw=False)

    if faces:
        face = faces[0]
        for id in idList:
            cv2.circle(img,face[id], 5, color, cv2.FILLED)

        leftUp = face[159]
        leftDown = face[23]
        leftLeft = face[130]
        leftRight = face[243]

        lengthVer,_ = detector.findDistance(leftUp,leftDown)
        lengthHor,_ = detector.findDistance(leftLeft,leftRight)

        cv2.line(img,leftUp,leftDown,color2,3)
        cv2.line(img,leftLeft,leftRight,color2,3)

        ratio = int((lengthVer/lengthHor)*100)
        ratioList.append(ratio)
        if len(ratioList) > 3:
            ratioList.pop(0)
        ratioAvg = sum(ratioList) / len(ratioList)

        if ratioAvg < 29 and counter == 0: # CuddlyScope: 39, Interated Cam: 29
            blinkCounter += 1
            color = color1
            counter = 1
        if counter != 0:
            counter +=1
            if counter > 10:
                counter = 0
                color = color2
        cvzone.putTextRect(img,f'Blink Count: {blinkCounter}', (50,100), colorR=color)
        imgPlot = plotY.update(ratioAvg, color)
        img = cv2.resize(img,(640,360))
        imgStack = cvzone.stackImages([img,imgPlot], 2,1)
    else:
        img = cv2.resize(img,(640,360))
        imgStack = cvzone.stackImages([img,img], 2,1)

    cv2.imshow('Image', imgStack)
    cv2.waitKey(1)

まずは、カメラで取得した映像を画面に表示するところからしましょう。 以下をコピペしてください。


    import cv2

cap = cv2.VideoCapture(0, cv2.CAP_DSHOW)

while True:
    sccess, img = cap.read()
    img = cv2.resize(img, (640,360))
    cv2.imshow("Imgage", img)
    cv2.waitKey(1)

これで一度実行してみてください。実行方法はターミナルでpython <ファイル名>か、右上の再生ボタンをクリックすることで出来ます。 ※VideoCaptureのところに0と入植していますが、ここを変えることで外部のUSBカメラに変更することもできます。 それでは次は、mediapipeを使用して顔の各点を取得していきましょう。以下をコピペしてください。


    import cv2
import cvzone
from cvzone.FaceMeshModule import FaceMeshDetector

cap = cv2.VideoCapture(0, cv2.CAP_DSHOW)
detector = FaceMeshDetector(maxFaces=1)

while True:
    if cap.get(cv2.CAP_PROP_POS_FRAMES) == cap.get(cv2.CAP_PROP_FRAME_COUNT):
        cap.set(cv2.CAP_PROP_POS_FRAMES, 0)

    sccess, img = cap.read()
    img, faces = detector.findFaceMesh(img, draw=True)

    img = cv2.resize(img, (640,360))
    cv2.imshow("Imgage", img)
    cv2.waitKey(1)

これに変更して実行すると顔上の点を取得できます。 ※findFaceMeshのところでdrawをFalseにすると描画を無くせます。 では次は、目の周りの点だけを取り出します。 以下をコピペしてください。


    import cv2
import cvzone
from cvzone.FaceMeshModule import FaceMeshDetector

cap = cv2.VideoCapture(0, cv2.CAP_DSHOW)
detector = FaceMeshDetector(maxFaces=1)

color1 = (255,0,255)
color2 = (0,200,0)
color = color1

idList = [22,23,24,26,110,157,158,159,160,130,243]

while True:
    if cap.get(cv2.CAP_PROP_POS_FRAMES) == cap.get(cv2.CAP_PROP_FRAME_COUNT):
        cap.set(cv2.CAP_PROP_POS_FRAMES, 0)

    sccess, img = cap.read()
    img, faces = detector.findFaceMesh(img, draw=False)

    if faces:
      face = faces[0]
      for id in idList:
        cv2.circle(img,face[id], 5, color, cv2.FILLED)
        
    img = cv2.resize(img, (640,360))
    cv2.imshow("Imgage", img)
    cv2.waitKey(1)

目の周辺の各点を取得することができました。 ここから、この点間の距離を取得して瞬き検出を行っていきます。 ここで、単純に距離を取得して閾値よりも短かった場合というような処理をしてしまうと目を開けたまま顔が後ろに下がると目が閉じていると判定されてしまいます。 そのため、目の横幅と縦幅の比率を取って検出を行っていきます。 以下をコピペしてください。


    import cv2
import cvzone
from cvzone.FaceMeshModule import FaceMeshDetector

cap = cv2.VideoCapture(0, cv2.CAP_DSHOW)
detector = FaceMeshDetector(maxFaces=1)

color1 = (255,0,255)
color2 = (0,200,0)
color = color1

idList = [22,23,24,26,110,157,158,159,160,130,243]

while True:
    if cap.get(cv2.CAP_PROP_POS_FRAMES) == cap.get(cv2.CAP_PROP_FRAME_COUNT):
        cap.set(cv2.CAP_PROP_POS_FRAMES, 0)

    sccess, img = cap.read()
    img, faces = detector.findFaceMesh(img, draw=False)

    if faces:
      face = faces[0]
      for id in idList:
        cv2.circle(img,face[id], 5, color, cv2.FILLED)
        leftUp = face[159]
        leftDown = face[23]
        leftLeft = face[130]
        leftRight = face[243]

        lengthVer,_ = detector.findDistance(leftUp,leftDown)
        lengthHor,_ = detector.findDistance(leftLeft,leftRight)

        cv2.line(img,leftUp,leftDown,color2,3)
        cv2.line(img,leftLeft,leftRight,color2,3)
        ratio = int((lengthVer/lengthHor)*100)
        print(ratio)
    img = cv2.resize(img, (640,360))
    cv2.imshow("Imgage", img)
    cv2.waitKey(1)

printの部分で、ターミナルに縦横の比率を出力しています。瞬きをすることによって値が変化し、顔を前後に動かしても値は余り変化していないことが分かります。 それでは、以上の数値を見てだいたいの閾値を決めてカウントしていきましょう。 一番最初に示した、完成形のコードをコピペしてください。


    import cv2
import cvzone
from cvzone.FaceMeshModule import FaceMeshDetector
from cvzone.PlotModule import LivePlot

cap = cv2.VideoCapture(0, cv2.CAP_DSHOW)
detector = FaceMeshDetector(maxFaces=1)
plotY = LivePlot(640,360,[20,50], invert=True)

idList = [22,23,24,26,110,157,158,159,160,130,243]
ratioList = []
blinkCounter = 0
counter = 0


color1 = (255,0,255)
color2 = (0,200,0)
color = color1

while True:

    if cap.get(cv2.CAP_PROP_POS_FRAMES) == cap.get(cv2.CAP_PROP_FRAME_COUNT):
        cap.set(cv2.CAP_PROP_POS_FRAMES, 0)

    success, img = cap.read()
    img, faces = detector.findFaceMesh(img, draw=False)

    if faces:
        face = faces[0]
        for id in idList:
            cv2.circle(img,face[id], 5, color, cv2.FILLED)

        leftUp = face[159]
        leftDown = face[23]
        leftLeft = face[130]
        leftRight = face[243]

        lengthVer,_ = detector.findDistance(leftUp,leftDown)
        lengthHor,_ = detector.findDistance(leftLeft,leftRight)

        cv2.line(img,leftUp,leftDown,color2,3)
        cv2.line(img,leftLeft,leftRight,color2,3)

        ratio = int((lengthVer/lengthHor)*100)
        ratioList.append(ratio)
        if len(ratioList) > 3:
            ratioList.pop(0)
        ratioAvg = sum(ratioList) / len(ratioList)

        if ratioAvg < 29 and counter == 0: # CuddlyScope: 39, Interated Cam: 29
            blinkCounter += 1
            color = color1
            counter = 1
        if counter != 0:
            counter +=1
            if counter > 10:
                counter = 0
                color = color2
        cvzone.putTextRect(img,f'Blink Count: {blinkCounter}', (50,100), colorR=color)
        imgPlot = plotY.update(ratioAvg, color)
        img = cv2.resize(img,(640,360))
        imgStack = cvzone.stackImages([img,imgPlot], 2,1)
    else:
        img = cv2.resize(img,(640,360))
        imgStack = cvzone.stackImages([img,img], 2,1)

    cv2.imshow('Image', imgStack)
    cv2.waitKey(1)

今回はcvzone のplotmoduleというものを使用して目の縦横比率を可視化しています。 以上より完成です!

'vite' は、内部コマンドまたは外部コマンド、 操作可能なプログラムまたはバッチ ファイルとして認識されていません。

Vuetifyを使用していたところ、題名のようなエラーに出くわした。

 

状況

家でプロジェクトを作成し、Githubにプッシュした後に別のパソコンにクローンした際に上記のエラーが出た。

解決策

結論としては、以下に点を確認・変更することで解決できた。

  1. nodeとnpmのバージョンが.node-versionのものかどうか確認するnode -vでも確認できます。
  2. node_modulesディレクトリを作成する。※大体gitignoreされているので、yarn installと打ち込んでnode_modulesディレクトリを作成しましょう。

Vuetify 3 公式サイト Installationの方法でエラーが出る

環境

  • PC:Windows
  • nodeバージョン管理ツール:nodist
  • node -v:16.19.1
  • npm -v:8.19.3

生じた問題

以下のサイトでVuetifyとViteを使ってプロジェクトを作ろうとしたところ、エラーが出てしまい、yarn devができませんでした。

vuetifyjs.com

 

エラー内容としては、以下のようなものでした。

 

failed to load config from <ファイルまでのパス>\vite.config.js error when starting dev server:
    Error: ENOENT: no such file or directory, open 'node:fs'
    ....

 

これを改善するために試行錯誤した結果、以下のようになりました。

 

    $npm init
    npm ERR! code MODULE_NOT_FOUND
    npm ERR! Cannot find module '○○○○○○'
    ....

このエラーが出てからは何をしようと同じエラーが出てしまいnpmが使えなくなってしまいました。

解決策

結論として、ダメだったのはnodeのバージョン管理ツールとして使用していたnodistかなと考えています。 以下サイトにも載っているように、今はnvm-windowsが流行っているようなので、そちらに変更することにしました。

de-milestones.com

まず、

「スタート」→「設定」→「アプリ」→「Nodist」→アンインストール

します。

※私のところにはなかったですが、Users/ユーザー名のディレクトリに.npmrcというファイルが残っていればそれも消しておいてください。

 

次に、以下サイトのDownload Now!をクリックして、最新バージョンのnvm-setup.zipをダウンロードした後に中に入っている.exeファイルをクリックして実行します。

github.com

 

※もし、既にnode.jsをダウンロードしている場合でも機能するようですが、もう必要ないと思うので消しておいた方がいいかもしれません。

nvm-windowsの使い方

利用可能なnodeのバージョンをインストールするためには、そのバージョンを指定して以下を打ち込みます。 nvm install xx.xx.x インストール済みバージョンを確認する場合は以下を打ち込みます。 nvm list 使用するバージョンを指定するためには以下を打ち込みます。 nvm use xx.xx.x ※nodeのバージョンを指定するだけでnpmも勝手にバージョンを合わせてくれます。nodist npm matchというコマンドを打ち込む手間が省けます!