react-webcamのスクリーンショットで取得する画像データのサイズを小さくしてみた
こんにちは、CX事業本部 IoT事業部の若槻です。
react-webcamを使用すると、Reactアプリにカメラ撮影機能を簡単に実装することができます。
今回は、react-webcamのスクリーンショットで取得する画像データのサイズを小さくしてみました。
現状の実装
下記のようなアプリケーションの実装があります。(こちらのエントリで実装したものとほぼ同じものです。)
import { useRef, useState, useCallback } from 'react'; import Webcam from 'react-webcam'; import { makeStyles } from '@material-ui/core/styles'; import './styles.css'; const useStyles = makeStyles(() => ({ webcam: { position: 'absolute', top: '0px', left: '0px', visibility: 'hidden' } })); export const App = () => { const classes = useStyles(); const [isCaptureEnable, setCaptureEnable] = useState< boolean >(false); const webcamRef = useRef<Webcam>(null); const [url, setUrl] = useState<string | null>(null); const capture = useCallback(() => { const imageSrc = webcamRef.current?.getScreenshot(); if (imageSrc) { setUrl(imageSrc); } }, [webcamRef]); return ( <> <header> <h1>カメラアプリ</h1> </header> {isCaptureEnable || ( <button onClick={() => setCaptureEnable(true)}> 開始 </button> )} {isCaptureEnable && ( <> <div> <button onClick={() => setCaptureEnable(false)}> 終了 </button> </div> <div> <Webcam audio={false} width={720} height={360} ref={webcamRef} screenshotFormat="image/jpeg" videoConstraints={{ width: 720, height: 360, facingMode: 'user' }} className={classes.webcam} /> </div> <button onClick={capture}>キャプチャ</button> </> )} {url && ( <> <div> <button onClick={() => { setUrl(null); }} > 削除 </button> </div> <div> <img src={url} alt="Screenshot" /> </div> </> )} </> ); };
この実装でreact-webcamのスクリーンショットにより取得される画像は、下記のようなピクセルサイズ720 * 360
のデータとなります。
データサイズは約44KBです。
課題
アプリケーションではこの取得した画像データ(約44KB)をサーバーに送信するのですが、その際にボトルネックとなったのが、AWS Lambda関数の非同期呼び出し時のペイロードの上限256KB
です。
画像3,4枚程度であれば大丈夫でしたが、それ以上の枚数を扱うユースケースがあったため、見直しをする必要性が出てきました。
対処
そこで取得するスクリーンショットの画像を縮小する対応を行いました。
アプリケーションのコードを下記のように変更します。react-webcamのwidth
とheight
プロパティの値をそれぞれ2/3とします。
<Webcam audio={false} width={540} height={270} ref={webcamRef} screenshotFormat="image/jpeg" videoConstraints={{ width: 720, height: 360, facingMode: 'user' }} className={classes.webcam} />
するとスクリーンショットの画像もピクセルサイズ540 * 270
となります。
またデータサイズも約30KBに軽減できました。
補足
videoConstraintsプロパティについて
react-webcamには他にもvideoConstraintsというプロパティがあります。このプロパティはWebAPIのMediaDevices.getUserMedia()
で使用する「MediaTrackConstraints」に対応するものです。getUserMedia()
を使用するとWebカメラやマイクから「メディアストリーム」を取得できます。メディアストリームの種類には音声(オーディオストリーム)と動画(ビデオストリーム)があり、動画の場合はWebカメラからストリームを取得する際の「制約」(MediaTrackConstraints)を設定できます。制約にはmax(最大値)、min(最小値)、ideal(理想値)、exact(必須値)を使用できます。
例えば下記であればwidthが理想が1280、最小が320、最大が1920でビデオストリームを取得します。
{ video: { width: { min: 320, ideal: 1280, max: 1920 }, } }
ちなみに下記のように指定した場合は既定でidealとなります。
{ video: { width: 1280, } }
widthプロパティとheightプロパティについて
一方で今回設定をしたwidthプロパティとheightプロパティは、react-webcamが取得したビデオストリームを投影する「Video」要素の縦横のピクセル値を表します。
今回のreact-webcamの実装の場合
以上を踏まえて、今回の当初のreact-webcamの実装である下記の場合は、「720 * 360
のビデオストリームがWebカメラから取得され、720 * 360
のVideo要素に投影される」という設定となります。
<Webcam audio={false} width={720} height={360} ref={webcamRef} screenshotFormat="image/jpeg" videoConstraints={{ width: 720, height: 360, facingMode: 'user' }} className={classes.webcam} />
せっかくなので色々パターンを試してみます。
下記のようにvideoConstraintsのheightをwidthに合わせて大きくすると、
<Webcam audio={false} width={720} height={360} ref={webcamRef} screenshotFormat="image/jpeg" videoConstraints={{ width: 720, height: 720, facingMode: 'user' }} className={classes.webcam} />
このような720 * 720
のスクリーンショットが取得できます。widthとheightはそれぞれ720と360ですが、react-webcamにおいてはwidthの指定のみがVideo要素のサイズに反映されるようです。
下記のようにvideoConstraintsのheightをwidthより大きくすると、
<Webcam audio={false} width={720} height={360} ref={webcamRef} screenshotFormat="image/jpeg" videoConstraints={{ width: 360, height: 720, facingMode: 'user' }} className={classes.webcam} />
このような縦長の720 * 1440
のスクリーンショットが取得できます。ビデオストリームでのwidthは360ですが、これがVideo要素への投影時に2倍の720に引き伸ばされ、また比例してheightも2倍の1440となっています。
下記のようにwidthプロパティを1/2にすると、
<Webcam audio={false} width={360} height={360} ref={webcamRef} screenshotFormat="image/jpeg" videoConstraints={{ width: 360, height: 720, facingMode: 'user' }} className={classes.webcam} />
このような縦横ともに1/2の360 * 720
のスクリーンショットが取得できます。
参考
以上