
react-webcamのスクリーンショットで取得する画像データのサイズを小さくしてみた
この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
こんにちは、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
のスクリーンショットが取得できます。
参考
以上