is this correct to alter contrast of an image using matrices? - flutter

so I have been trying to alter an image's contrast with matrices and this is what I have come up with:
final defaultColorMatrix = const <double>[
1, 0, 0, 0, 0,
0, 1, 0, 0, 0,
0, 0, 1, 0, 0,
0, 0, 0, 1, 0,
];
List<double> calculateContrastMatrix(double contrast) {
final m = List<double>.from(defaultColorMatrix);
m[0] = contrast;
m[6] = contrast;
m[12] = contrast;
m[5] = (1 - contrast) / 2;
m[10] = (1 - contrast) / 2;
m[15] = (1 - contrast) / 2;
return m;
being contrast and adjustable value between 0 and 1
it is giving me sub optimal results

I just realized that the last column is not m[5], m[10], m[15] but m[4], m[9], m[14]. I forgot that dart's array index starts at 0.
I also forgot that the last column in flutter matrices is not normalized to it expects values between 0-255 so the correct solution is:
List<double> calculateContrastMatrix(double contrast) {
final m = List<double>.from(defaultColorMatrix);
m[0] = contrast;
m[6] = contrast;
m[12] = contrast;
m[4] = ((1 - contrast) / 2) * 255;
m[9] = ((1 - contrast) / 2) * 255;
m[14] = ((1 - contrast) / 2) * 255;
return m;

Related

raspberry pi OSError; savedModel file does not exist at

This code does not have an error when running on a computer, but when I move all the files and run it on a Raspberry Pi, I get this error. Where and how to fix it?
OSError; savedModel file does not exist at: models/mask_detector.model/{saved_model.pbtxt|saved_model.pb}
from tensorflow.keras.applications.mobilenet_v2 import preprocess_input
from tensorflow.keras.models import load_model
import numpy as np
import cv2
facenet = cv2.dnn.readNet('models/deploy.prototxt', 'models/res10_300x300_ssd_iter_140000.caffemodel')
model = load_model('models/mask_detector.model')
cap = cv2.VideoCapture(0)
i = 0
while cap.isOpened():
ret, img = cap.read()
if not ret:
break
h, w = img.shape[:2]
blob = cv2.dnn.blobFromImage(img, scalefactor=1., size=(300, 300), mean=(104., 177., 123.))
facenet.setInput(blob)
dets = facenet.forward()
result_img = img.copy()
for i in range(dets.shape[2]):
confidence = dets[0, 0, i, 2]
if confidence < 0.5:
continue
x1 = int(dets[0, 0, i, 3] * w)
y1 = int(dets[0, 0, i, 4] * h)
x2 = int(dets[0, 0, i, 5] * w)
y2 = int(dets[0, 0, i, 6] * h)
face = img[y1:y2, x1:x2]
face_input = cv2.resize(face, dsize=(224, 224))
face_input = cv2.cvtColor(face_input, cv2.COLOR_BGR2RGB)
face_input = preprocess_input(face_input)
face_input = np.expand_dims(face_input, axis=0)
mask, nomask = model.predict(face_input).squeeze()
if mask > nomask:
color = (0, 255, 0)
label = 'Mask %d%%' % (mask * 100)
else:
color = (0, 0, 255)
label = 'No Mask %d%%' % (nomask * 100)
cv2.rectangle(result_img, pt1=(x1, y1), pt2=(x2, y2), thickness=2, color=color, lineType=cv2.LINE_AA)
cv2.putText(result_img, text=label, org=(x1, y1 - 10), fontFace=cv2.FONT_HERSHEY_SIMPLEX, fontScale=0.8,
color=color, thickness=2, lineType=cv2.LINE_AA)
cv2.imshow('img',result_img)
if cv2.waitKey(1) & 0xFF == ord('q'):
break

Building a Perspective Projection Matrix

my first post here but hopefully I can explain my dilemma with building a perspective projection matrix similar to the one in OpenGL. Being new to the 3D graphics space, I'm having trouble understanding what to do after multiplying my matrix after using a perspective projection multiplication. I'm attempting to create this in Flutter but it should be a moot point as I believe my conversion is off.
Here is what I have:
var center = {
'x': size.width / 2,
'y': size.height / 2
};
List points = [];
points.add(createVector(-50, -50, -50, center));
points.add(createVector(50, -50, -50, center));
points.add(createVector(50, 50, -50, center));
points.add(createVector(-50, 50, -50, center));
points.add(createVector(-50, -50, 50, center));
points.add(createVector(50, -50, 50, center));
points.add(createVector(50, 50, 50, center));
points.add(createVector(-50, 50, 50, center));
for (int i = 0; i < points.length; i++) {
var matrix = matmul(projection, points[i]);
var w = matrix[3][0];
projected.add(
Offset(
(matrix[0][0] / w),
(matrix[1][0] / w)
)
);
}
And these are the 2 custom functions I've created:
List createVector(x, y, z, center) {
return [
[center['x'] + x],
[center['y'] + y],
[z],
[0]
];
}
List matmul(a, b) {
int colsA = a[0].length;
int rowsA = a.length;
int colsB = b[0].length;
int rowsB = b.length;
if (colsA != rowsB) {
return null;
}
List result = [];
for (int j = 0; j < rowsA; j++) {
result.add([]);
for (int i = 0; i < colsB; i++) {
double sum = 0.0;
for (int n = 0; n < colsA; n++) {
sum += a[j][n] * b[n][i];
}
result[j].add(sum);
}
}
return result;
}
My projection matrix that I'm multiplying each point with is:
var aspect = size.width / size.height;
var fov = 100;
var near = 200;
var far = 300;
List projection = [
[1 / (aspect * tan(fov / 2)), 0, 0, 0],
[0, 1 / (tan(fov / 2)), 0, 0],
[0, 0, (near + far) / (near - far), (2 * near * far) / (near - far)],
[0, 0, -1, 0]
];
I believe I am using the correct projection matrix to multiply each vector point that I have. The only thing is, after I get the result from this multiplication, I'm not entirely sure what to do with the resultant vector. I've read about the perspective divide so I am dividing the x, y and z values by the 4th values but I could be incorrect.
Any insight or help is much appreciated. Have been stumped for a long time as I have been learning this online on my own.
In OpenGL the projection matrix turns from a right handed system to a left handed system. See Right-hand rule). This is accomplished by mirroring the z axis.
The terms in the 3rd column have to be inverted (- (near+far) / (near-far) respectively - (2*near*far) / (near-far)):
List projection = [
[1 / (aspect * tan(fov/2)), 0, 0, 0],
[0, 1 / (tan(fov/2)), 0, 0],
[0, 0, - (near+far) / (near-far), - (2*near*far) / (near-far)],
[0, 0, -1, 0]
];
The perspective projection matrix defines a Viewing frustum. It defines a 3 dimensional space (clip space) which is projected on the 2 dimensional viewport.
In OponGL all the geometry which is not in clip space is clipped. You have to ensure that the geometry is in between the near and far plane.

Generate random movement for a point in 3D space

I want to simulate a point that moves with random vibration around a mean position (let's say around the position [X, Y, Z] = [0,0,0]). The first solution that I found is to sum a couple of sinusoids for each axis based on the following equation:
<img src="https://latex.codecogs.com/gif.latex?\sum_{i&space;=&space;1}^n&space;A_i&space;\sin(\omega_i&space;t&plus;\phi)" title="\sum_{i = 1}^n A_i \sin(\omega_i t+\phi)" />
where A_i is a normal random amplitude, and omega_i is a normal random frequency. I have not tested the phase yet, so I leave it to zero for now. I generated figures of the expect normal distribution and equation results with the following approach. I tried multiple values of N and I'm not sure that the equation is giving a normally distributed results. Is my approach correct? Is there a better way to generate random vibration?
For such a task, you may find useful Perlin Noise or even Fractal Brownian Motion noise. See this implementation in JavaScript:
class Utils {
static Lerp(a, b, t) {
return (1 - t) * a + t * b;
}
static Fade(t) {
return t * t * t * (t * (t * 6 - 15) + 10);
}
}
class Noise {
constructor() {
this.p = [];
this.permutationTable = [];
this.grad3 = [[1, 1, 0], [-1, 1, 0], [1, -1, 0],
[-1, -1, 0], [1, 0, 1], [-1, 0, 1],
[1, 0, -1], [-1, 0, -1], [0, 1, 1],
[0, -1, 1], [0, 1, -1], [0, -1, -1]];
for (let i = 0; i < 256; i++)
this.p[i] = Math.floor(Math.random() * 256);
for (let i = 0; i < 512; i++)
this.permutationTable[i] = this.p[i & 255];
}
PerlinDot(g, x, y, z) {
return g[0] * x + g[1] * y + g[2] * z;
}
PerlinNoise(x, y, z) {
let a = Math.floor(x);
let b = Math.floor(y);
let c = Math.floor(z);
x = x - a;
y = y - b;
z = z - c;
a &= 255;
b &= 255;
c &= 255;
let gi000 = this.permutationTable[a + this.permutationTable[b + this.permutationTable[c]]] % 12;
let gi001 = this.permutationTable[a + this.permutationTable[b + this.permutationTable[c + 1]]] % 12;
let gi010 = this.permutationTable[a + this.permutationTable[b + 1 + this.permutationTable[c]]] % 12;
let gi011 = this.permutationTable[a + this.permutationTable[b + 1 + this.permutationTable[c + 1]]] % 12;
let gi100 = this.permutationTable[a + 1 + this.permutationTable[b + this.permutationTable[c]]] % 12;
let gi101 = this.permutationTable[a + 1 + this.permutationTable[b + this.permutationTable[c + 1]]] % 12;
let gi110 = this.permutationTable[a + 1 + this.permutationTable[b + 1 + this.permutationTable[c]]] % 12;
let gi111 = this.permutationTable[a + 1 + this.permutationTable[b + 1 + this.permutationTable[c + 1]]] % 12;
let n000 = this.PerlinDot(this.grad3[gi000], x, y, z);
let n100 = this.PerlinDot(this.grad3[gi100], x - 1, y, z);
let n010 = this.PerlinDot(this.grad3[gi010], x, y - 1, z);
let n110 = this.PerlinDot(this.grad3[gi110], x - 1, y - 1, z);
let n001 = this.PerlinDot(this.grad3[gi001], x, y, z - 1);
let n101 = this.PerlinDot(this.grad3[gi101], x - 1, y, z - 1);
let n011 = this.PerlinDot(this.grad3[gi011], x, y - 1, z - 1);
let n111 = this.PerlinDot(this.grad3[gi111], x - 1, y - 1, z - 1);
let u = Utils.Fade(x);
let v = Utils.Fade(y);
let w = Utils.Fade(z);
let nx00 = Utils.Lerp(n000, n100, u);
let nx01 = Utils.Lerp(n001, n101, u);
let nx10 = Utils.Lerp(n010, n110, u);
let nx11 = Utils.Lerp(n011, n111, u);
let nxy0 = Utils.Lerp(nx00, nx10, v);
let nxy1 = Utils.Lerp(nx01, nx11, v);
return Utils.Lerp(nxy0, nxy1, w);
}
FractalBrownianMotion(x, y, z, octaves, persistence) {
let total = 0;
let frequency = 1;
let amplitude = 1;
let maxValue = 0;
for(let i = 0; i < octaves; i++) {
total = this.PerlinNoise(x * frequency, y * frequency, z * frequency) * amplitude;
maxValue += amplitude;
amplitude *= persistence;
frequency *= 2;
}
return total / maxValue;
}
}
With Fractal Brownian Motion can have huge control about the randomness of distribution. You can set the scale, initial offset and its increment for each axis, octaves, and persistence. You can generate as many positions you like by incrementing the offsets, like this:
const NUMBER_OF_POSITIONS = 1000;
const X_OFFSET = 0;
const Y_OFFSET = 0;
const Z_OFFSET = 0;
const X_SCALE = 0.01;
const Y_SCALE = 0.01;
const Z_SCALE = 0.01;
const OCTAVES = 8;
const PERSISTENCE = 2;
const T_INCREMENT = 0.1;
const U_INCREMENT = 0.01;
const V_INCREMENT = 1;
let noise = new Noise();
let positions = [];
let i = 0, t = 0, u = 0, v = 0;
while(i <= NUMBER_OF_POSITIONS) {
let position = {x:0, y:0, z:0};
position.x = noise.FractalBrownianMotion((X_OFFSET + t) * X_SCALE, (Y_OFFSET + t) * Y_SCALE, (Z_OFFSET + t) * Z_SCALE, OCTAVES, PERSISTENCE);
position.y = noise.FractalBrownianMotion((X_OFFSET + u) * X_SCALE, (Y_OFFSET + u) * Y_SCALE, (Z_OFFSET + u) * Z_SCALE, OCTAVES, PERSISTENCE);
position.z = noise.FractalBrownianMotion((X_OFFSET + v) * X_SCALE, (Y_OFFSET + v) * Y_SCALE, (Z_OFFSET + v) * Z_SCALE, OCTAVES, PERSISTENCE);
positions.push(position);
t += T_INCREMENT;
u += U_INCREMENT;
v += V_INCREMENT;
i++;
}
Positions you get with these options would look similar to these:
...
501: {x: 0.0037344935483775883, y: 0.1477509219864437, z: 0.2434570202517206}
502: {x: -0.008955635460317357, y: 0.14436114483299245, z: -0.20921147024725012}
503: {x: -0.06021806450587406, y: 0.14101769272762685, z: 0.17093922757597568}
504: {x: -0.05796055906294283, y: 0.13772732578136435, z: 0.0018755951606465138}
505: {x: 0.02243901814464688, y: 0.13448621540816477, z: 0.013341084536334057}
506: {x: 0.05074194554980439, y: 0.1312810723109357, z: 0.15821600463130164}
507: {x: 0.011075140752144507, y: 0.12809058766450473, z: 0.04006055269090941}
508: {x: -0.0000031848272303249632, y: 0.12488712875549206, z: -0.003957905411646261}
509: {x: -0.0029798194097060307, y: 0.12163862278870072, z: -0.1988934273517602}
510: {x: -0.008762098499026483, y: 0.11831055728747841, z: 0.02222898347134993}
511: {x: 0.01980289423585394, y: 0.11486802263767962, z: -0.0792283303765883}
512: {x: 0.0776034130079849, y: 0.11127772191732693, z: -0.14141576745502138}
513: {x: 0.08695806478169149, y: 0.10750987521108693, z: 0.049654228704645}
514: {x: 0.036915612100698, y: 0.10353995005320946, z: 0.00033977899920740567}
515: {x: 0.0025923223158845687, y: 0.09935015632822117, z: -0.00952549797548823}
516: {x: 0.0015456084571764527, y: 0.09493065267319889, z: 0.12609905321632175}
517: {x: 0.0582996941155056, y: 0.09028042189611517, z: -0.27532974820612816}
518: {x: 0.19186052966982514, y: 0.08540778482478142, z: -0.00035058098387404606}
519: {x: 0.27063961068049447, y: 0.08033053495775729, z: -0.07737309686568927}
520: {x: 0.20318957178662056, y: 0.07507568989311474, z: -0.14633819135757353}
...
Note: for efficiency, it's a good idea generate all positions only once into an array of positions like in this example, and then in some animation loop just assigning positions to your point from this array one by one.
Bonus: Here you can see how those values affect the distribution of multiple points by playing around with real-time response control panel:
https://marianpekar.github.io/fbm-space/
References:
https://en.wikipedia.org/wiki/Fractional_Brownian_motion
https://en.wikipedia.org/wiki/Perlin_noise

Translate Transformation Matrices for Alpha Blending

I'm trying to introduce alpha blending into the MATLAB panoramic stitching example. The algorithm successfully blends, but the stitched image is translated, when using the example's "tforms" transformation matrices.
The alpha blending code is here:
%% merge images using Alpha blending
% input: imgs - source images
% mask - image mask
% transforms - transformation matrices to transform each images
% into the new coordinate system
% newHeight, newWidth - size of the new coordinate system
% output: newImg - merged image
function [ newImg ] = alphaBlend( imgs, mask, transforms, newHeight, newWidth )
% image information
height = size(imgs, 1);
width = size(imgs, 2);
nChannels = size(imgs, 3);
nImgs = size(imgs, 4);
% alpha mask
mask = imcomplement(mask);
mask(1, :) = 1;
mask(end, :) = 1;
mask(:, 1) = 1;
mask(:, end) = 1;
mask = bwdist(mask, 'euclidean');
mask = mask ./ max(max(mask));
% backward transformation
backTransforms = zeros(size(transforms));
for i = 1 : nImgs
backTransforms(:, :, i) = inv(transforms(:, :, i));
end
% image merging
newImg = zeros([newHeight newWidth nChannels], 'uint8');
for y = 1 : newHeight
for x = 1 : newWidth
% p1 = [y; x; 1];
p1 = [x; y; 1];
pixelSum = zeros(nChannels, 1);
alphaSum = 0;
for k = 1 : nImgs
% p2 = backTransforms(:, :, k) * p1;
p2 = p1' * backTransforms(:,:,k);
p2 = p2 ./ p2(3);
xx = p2(1);
yy = p2(2);
p2 = [yy; xx; 1];
if p2(1) >= 1 && p2(1) < height && p2(2) >= 1 && p2(2) < width
i = floor(p2(2));
a = p2(2) - i;
j = floor(p2(1));
b = p2(1) - j;
pixel = (1 - a) * (1 - b) * imgs(j, i, :, k)...
+ a * (1 - b) * imgs(j, i + 1, :, k)...
+ a * b * imgs(j + 1, i + 1, :, k)...
+ (1 - a) * b * imgs(j + 1, i, :, k);
alpha = (1 - a) * (1 - b) * mask(j, i)...
+ a * (1 - b) * mask(j, i + 1)...
+ a * b * mask(j + 1, i + 1)...
+ (1 - a) * b * mask(j + 1, i);
pixelSum = pixelSum + double(squeeze(pixel)) * double(alpha);
alphaSum = alphaSum + double(alpha);
end
end
newImg(y, x, :) = pixelSum / alphaSum;
end
end
end
After the Panoramic Stitching example tforms matrices have been formed by step 4 , I try translating the image this way:
mask = ones(imageSize(1),imageSize(2));
% Create the panorama.
% Alpha blending
horiz = 200;
verti = 100;
Translate = [1, 0, 0; 0, 1, 0; horiz, verti, 1];
transforms = Translate * tforms(1).T;
for i =1:numel(tforms) transforms(:,:,i) = Translate * tforms(i).T; end
panorama1 = alphaBlend( temp, mask, transforms, height, width );
But, the resulting image overlap is off. How do I translate the tforms matrix, in order to translate the stitched panoramic image?

Implement Sliding Window Algo in Matlab

I want to implement Sliding Window Algorithm.
The goal is to show all my window(s).
But i just got 1 window only.
Here's my code:
clc;clear all;`
image = imread('tabTes.png');
imageWidth = size(image, 2);
imageHeight = size(image, 1);
windowWidth = 100;
windowHeight = 100;
for j = 1:imageHeight - imageHeight + 1
for i = 1:imageWidth - imageWidth + 1
SlideWindow = image(j:j + windowHeight - 1, i:i + windowWidth - 1, :);
end
end
figure
imshow(SlideWindow);
Try this:
clc;clear all;`
image = imread('tabTes.png');
imageWidth = size(image, 2);
imageHeight = size(image, 1);
windowWidth = 100;
windowHeight = 100;
for j = 1:imageHeight - windowHeight + 1
for i = 1:imageWidth - windowWidth + 1
SlideWindow = image(j:j + windowHeight - 1, i:i + windowWidth - 1, :);
figure
imshow(SlideWindow);
end
end
Be careful, though. This will generate a lot of figures.