Skip to content

Instantly share code, notes, and snippets.

@yosun
Forked from SqrtRyan/gist:4f250b4e11f52d9818064942156659d2
Last active February 6, 2025 19:43
Show Gist options
  • Save yosun/7116e093ede383d8ca6eb610056ecc7c to your computer and use it in GitHub Desktop.
Save yosun/7116e093ede383d8ca6eb610056ecc7c to your computer and use it in GitHub Desktop.
using UnityEngine;
using OpenCVForUnity.CoreModule;
using OpenCVForUnity.ImgprocModule;
using OpenCVForUnity.UnityUtils;
using OpenCVForUnity.VideoioModule;
using System.Collections.Generic;
public class LowRankWebcam : MonoBehaviour
{
VideoCapture capture;
Mat cumulativeImage;
Mat displayMat;
Texture2D texture;
int frameWidth = 512;
int frameHeight = 512;
void Start()
{
capture = new VideoCapture();
capture.open(0);
if (!capture.isOpened())
{
Debug.LogError("Failed to open webcam!");
return;
}
cumulativeImage = new Mat(frameHeight, frameWidth, CvType.CV_32FC3, new Scalar(0));
displayMat = new Mat();
texture = new Texture2D(frameWidth, frameHeight);
GetComponent<Renderer>().material.mainTexture = texture;
}
void ApproximateMatrixByRank(Mat src, int rank, Mat dst)
{
if (rank <= 0 || rank > Mathf.Min(src.rows(), src.cols()))
{
src.copyTo(dst);
return;
}
Mat U = new Mat(), S = new Mat(), Vt = new Mat();
Core.SVDecomp(src, S, U, Vt, Core.SVD_FULL_UV);
Mat Ur = U.colRange(0, rank);
Mat Vtr = Vt.rowRange(0, rank);
Mat diagS = Mat.zeros(rank, rank, CvType.CV_32F);
for (int i = 0; i < rank; i++)
{
diagS.put(i, i, S.get(i, 0)[0]);
}
Mat temp = new Mat();
Core.gemm(Ur, diagS, 1, new Mat(), 0, temp);
Core.gemm(temp, Vtr, 1, new Mat(), 0, dst);
}
void Update()
{
if (!capture.isOpened() || !capture.grab()) return;
Mat frame = new Mat();
capture.retrieve(frame);
if (frame.empty())
{
frame.Dispose();
return;
}
// Preprocessing
Imgproc.resize(frame, frame, new Size(frameWidth, frameHeight));
Imgproc.cvtColor(frame, frame, Imgproc.COLOR_BGR2RGB);
Mat currentFrame = new Mat();
frame.convertTo(currentFrame, CvType.CV_32FC3, 1.0 / 255.0);
frame.Dispose();
// Calculate difference
Mat delta = new Mat();
Core.subtract(currentFrame, cumulativeImage, delta);
Core.multiply(delta, new Scalar(1.51), delta);
currentFrame.Dispose();
// Process channels
List<Mat> channels = new List<Mat>();
Core.split(delta, channels);
delta.Dispose();
for (int i = 0; i < 3; i++)
{
ApproximateMatrixByRank(channels[i], 1, channels[i]);
}
Mat approximatedDelta = new Mat();
Core.merge(channels, approximatedDelta);
channels.ForEach(m => m.Dispose());
// Update cumulative image
Core.add(cumulativeImage, approximatedDelta, cumulativeImage);
approximatedDelta.Dispose();
// Clamp values
Core.min(cumulativeImage, new Scalar(1.0), cumulativeImage);
Core.max(cumulativeImage, new Scalar(0.0), cumulativeImage);
// Display
if (!cumulativeImage.empty())
{
cumulativeImage.convertTo(displayMat, CvType.CV_8UC3, 255);
Utils.matToTexture2D(displayMat, texture);
}
}
void OnDestroy()
{
if (capture != null) capture.release();
if (cumulativeImage != null) cumulativeImage.Dispose();
if (displayMat != null) displayMat.Dispose();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment