Forked from SqrtRyan/gist:4f250b4e11f52d9818064942156659d2
Last active
February 6, 2025 19:43
-
-
Save yosun/7116e093ede383d8ca6eb610056ecc7c to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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