I've made a function to find a color within a image, and return x, y. Now I need to add a new function, where I can find a color with a given tolerence. Should be easy?
Code to find color in image, and return x, y:
def FindColorIn(r,g,b, xmin, xmax, ymin, ymax):
image = ImageGrab.grab()
for x in range(xmin, xmax):
for y in range(ymin,ymax):
px = image.getpixel((x, y))
if px[0] == r and px[1] == g and px[2] == b:
return x, y
def FindColor(r,g,b):
image = ImageGrab.grab()
size = image.size
pos = FindColorIn(r,g,b, 1, size[0], 1, size[1])
return pos
Outcome:
Taken from the answers the normal methods of comparing two colors are in Euclidean distance, or Chebyshev distance.
I decided to mostly use (squared) euclidean distance, and multiple different color-spaces. LAB, deltaE (LCH), XYZ, HSL, and RGB. In my code, most color-spaces use squared euclidean distance to compute the difference.
For example with LAB, RGB and XYZ a simple squared euc. distance does the trick:
if ((X-X1)^2 + (Y-Y1)^2 + (Z-Z1)^2) <= (Tol^2) then
...
LCH, and HSL is a little more complicated as both have a cylindrical hue, but some piece of math solves that, then it's on to using squared eucl. here as well.
In most these cases I've added "separate parameters" for tolerance for each channel (using 1 global tolerance, and alternative "modifiers" HueTol := Tolerance * hueMod or LightTol := Tolerance * LightMod).
It seems like colorspaces built on top of XYZ (LAB, LCH) does perform best in many of my scenarios. Tho HSL yields very good results in some cases, and it's much cheaper to convert to from RGB, RGB is also great tho, and fills most of my needs.
Computing distances between RGB colours, in a way that's meaningful to the eye, isn't as easy a just taking the Euclidian distance between the two RGB vectors.
There is an interesting article about this here: http://www.compuphase.com/cmetric.htm
The example implementation in C is this:
typedef struct {
unsigned char r, g, b;
} RGB;
double ColourDistance(RGB e1, RGB e2)
{
long rmean = ( (long)e1.r + (long)e2.r ) / 2;
long r = (long)e1.r - (long)e2.r;
long g = (long)e1.g - (long)e2.g;
long b = (long)e1.b - (long)e2.b;
return sqrt((((512+rmean)*r*r)>>8) + 4*g*g + (((767-rmean)*b*b)>>8));
}
It shouldn't be too difficult to port to Python.
EDIT:
Alternatively, as suggested in this answer, you could use HLS and HSV. The colorsys module seems to have functions to make the conversion from RGB. Its documentation also links to these pages, which are worth reading to understand why RGB Euclidian distance doesn't really work:
http://www.poynton.com/ColorFAQ.html
http://www.cambridgeincolour.com/tutorials/color-space-conversion.htm
EDIT 2:
According to this answer, this library should be useful: http://code.google.com/p/python-colormath/
Here is an optimized Python version adapted from Bruno's asnwer:
def ColorDistance(rgb1,rgb2):
'''d = {} distance between two colors(3)'''
rm = 0.5*(rgb1[0]+rgb2[0])
d = sum((2+rm,4,3-rm)*(rgb1-rgb2)**2)**0.5
return d
usage:
>>> import numpy
>>> rgb1 = numpy.array([1,1,0])
>>> rgb2 = numpy.array([0,0,0])
>>> ColorDistance(rgb1,rgb2)
2.5495097567963922
Instead of this:
if px[0] == r and px[1] == g and px[2] == b:
Try this:
if max(map(lambda a,b: abs(a-b), px, (r,g,b))) < tolerance:
Where tolerance is the maximum difference you're willing to accept in any of the color channels.
What it does is to subtract each channel from your target values, take the absolute values, then the max of those.
Assuming that rtol, gtol, and btol are the tolerances for r,g, and b respectively, why not do:
if abs(px[0]- r) <= rtol and \
abs(px[1]- g) <= gtol and \
abs(px[2]- b) <= btol:
return x, y
Here's a vectorised Python (numpy) version of Bruno and Developer's answers (i.e. an implementation of the approximation derived here) that accepts a pair of numpy arrays of shape (x, 3) where individual rows are in [R, G, B] order and individual colour values ∈[0, 1].
You can reduce it two a two-liner at the expense of readability. I'm not entirely sure whether it's the most optimised version possible, but it should be good enough.
def colour_dist(fst, snd):
rm = 0.5 * (fst[:, 0] + snd[:, 0])
drgb = (fst - snd) ** 2
t = np.array([2 + rm, 4 + 0 * rm, 3 - rm]).T
return np.sqrt(np.sum(t * drgb, 1))
It was evaluated against Developer's per-element version above, and produces the same results (save for floating precision errors in two cases out of one thousand).
A cleaner python implementation of the function stated here, the function takes 2 image paths, reads them using cv.imread and the outputs a matrix with each matrix cell having difference of colors. you can change it to just match 2 colors easily
import numpy as np
import cv2 as cv
def col_diff(img1, img2):
img_bgr1 = cv.imread(img1) # since opencv reads as B, G, R
img_bgr2 = cv.imread(img2)
r_m = 0.5 * (img_bgr1[:, :, 2] + img_bgr2[:, :, 2])
delta_rgb = np.square(img_bgr1- img_bgr2)
cols_diffs = delta_rgb[:, :, 2] * (2 + r_m / 256) + delta_rgb[:, :, 1] * (4) +
delta_rgb[:, :, 0] * (2 + (255 - r_m) / 256)
cols_diffs = np.sqrt(cols_diffs)
# lets normalized the values to range [0 , 1]
cols_diffs_min = np.min(cols_diffs)
cols_diffs_max = np.max(cols_diffs)
cols_diffs_normalized = (cols_diffs - cols_diffs_min) / (cols_diffs_max - cols_diffs_min)
return np.sqrt(cols_diffs_normalized)
Simple:
def eq_with_tolerance(a, b, t):
return a-t <= b <= a+t
def FindColorIn(r,g,b, xmin, xmax, ymin, ymax, tolerance=0):
image = ImageGrab.grab()
for x in range(xmin, xmax):
for y in range(ymin,ymax):
px = image.getpixel((x, y))
if eq_with_tolerance(r, px[0], tolerance) and eq_with_tolerance(g, px[1], tolerance) and eq_with_tolerance(b, px[2], tolerance):
return x, y
from pyautogui source code
def pixelMatchesColor(x, y, expectedRGBColor, tolerance=0):
r, g, b = screenshot().getpixel((x, y))
exR, exG, exB = expectedRGBColor
return (abs(r - exR) <= tolerance) and (abs(g - exG) <= tolerance) and (abs(b - exB) <= tolerance)
you just need a little fix and you're ready to go.
Here is a simple function that does not require any libraries:
def color_distance(rgb1, rgb2):
rm = 0.5 * (rgb1[0] + rgb2[0])
rd = ((2 + rm) * (rgb1[0] - rgb2[0])) ** 2
gd = (4 * (rgb1[1] - rgb2[1])) ** 2
bd = ((3 - rm) * (rgb1[2] - rgb2[2])) ** 2
return (rd + gd + bd) ** 0.5
assuming that rgb1 and rgb2 are RBG tuples
I have a for loop that shifts a signal over a certain amount and appends it to an array. How can I vectorize the circshift section so I don't need to use the for loop?
fs_rate=10
len_of_sig=1; %length of signal in seconds
t=linspace(0,len_of_sig,fs_rate*len_of_sig);
y=.5*sin(2*pi*1*t);
for aa=1:length(y)
y_new(aa,:)=circshift(y,[1,aa+3]); %shifts signal and appends to array
end
plot(t,y_new)
PS: I'm using Octave 4.2.2 Ubuntu 18.04 64bit
You can use the gallery to create a circular matrix after using circshift for your base shift:
base_shift = 4;
fs_rate = 10;
len_of_sig = 1; # length of signal in seconds
t = linspace (0, len_of_sig, fs_rate*len_of_sig);
y = .5 * sin (2*pi*1*t);
y = gallery ("circul", circshift (y, [1 base_shift]));
Or if you want to know how it was implemented, take a look at its source code type gallery
I'm writing a code to solve Ax=b using MATLAB's x=A\B. I believe my problem lies within getting the data from the files into the array. Right now, the solution vector is coming out to be a load of 0's
The matrices I'm using have 10 rows respectively. They are aligned correctly in the text files.
% solve a linear system Ax = b by reading A and b from input file
% and then writing x on output file.
clear;
clc;
input_filename = 'my_input.txt';
output_filename = 'my_output.txt';
% read data from file
fileID = fopen('a_matrix.txt', 'r');
formatSpec = '%d %f';
sizeA = [10 Inf];
A = load('b_matrix.txt');
A = A'
file2ID = fopen('b_matrix.txt','r');
formatSpec2 = '%d %f';
sizeB = [10 Inf];
b = load('b_matrix.txt');
fclose(file2ID);
b = b'
% solve the linear system
x = A\b;
% write output data on file
dlmwrite('my_output.txt',x,'delimiter',',','precision',4);
% print screen
fprintf('Solution vector is: \n');
fprintf('%4.2f \n', x);
I answered my own question but I felt the need to share in case anyone else has similar troubles.
% solve a linear system Ax = b by reading A and b from input file
% and then writing x on output file.
clear;
clc;
input_filename = 'my_input.txt';
output_filename = 'my_output.txt';
% read data from file
f = textread('a_matrix.txt', '%f');
vals = reshape(f, 11, []).';
A = vals(:,1:10);
b = vals(:,11);
% solve the linear system
x = A\b;
% write output data on file
dlmwrite('my_output.txt',x,'delimiter',',','precision',4);
% print screen
fprintf('Solution vector is: \n');
fprintf('%4.2f \n', x);
I ended up combining the 'a' and 'b' matrix into a single text file for simplicity. Now, MATLAB reads data in by columns, so it is necessary to use 'reshape' in order to fit the data within the array correctly. Then, I filtered out the information from the single matrix by columns, using the 'vals' function as seen in my code. The 'A' matrix is essentially all numbers in columns 1 through 10, while the 'B' matrix is the 11th (and final) column.
Using MATLAB's x=A\b function, I was able to solve the linear system of equations.
I am trying to plot the periodic functions in matlab of the following equation:
using the following code:
tn= 25;
kn= 7;
time=0:1:200;
f=0;
for t= (-tn):1:(tn)
for k = (-kn):1:(kn)
s1=((1j)*k*exp(-abs(k)));
s2=exp((1j)*k*((2*pi)/50));
f=f+(s1*s2);
end
tval = (f*exp(t));
fs(1,t+1) = tval;
end
I am having trouble understanding why I am not able to see the plot. Is there another way to plot complex numbers in Matlab?
Am I going about this the wrong way? I am simply trying to plot fs against time (could be from 0-200 or -100 - 100 for all I care) and see the periodic function so I can go ahead and manipulate it but I can't seem to even get the correct plot.
I tried using the symsum function in matlab but could not figure it out. I understand C and C++ and felt like this approach was more intuitive for me.
edit:
x(1:101)=0;
t(1:101)=0;
for n=0:1:100
t(n+1)=n;
for k=-100:1:100
x(n+1)=x(n+1)+abs(sin((k*pi)/2))*exp(1j*k*((2*pi)/50)*n);
end;
end;
I plotted the function using the following code. Why do our imaginary plots look different?
I don't have Matlab, but here the same in Python (using Numpy & Matplotlib which are very similar to Matlab):
import numpy as np
import matplotlib.pyplot as p
%matplotlib inline
t= np.arange(0,100,0.1)
s=np.zeros(len(t))
for k in range(40):
s=s+ np.abs(np.sin (k*np.pi/2)) * np.exp( 1j*k *2*np.pi/50.0*t) # pos k
s=s+ np.abs(np.sin (-k*np.pi/2)) * np.exp(- 1j*k *2*np.pi/50.0*t) # negative k
# the cosine is symmetric so it survives adding the negatives,
# the sines get cancelled as they are antisymmetric for the negative k,
# so the imaginary part is identically zero.
p.subplot(311)
p.plot(np.real(s))
p.subplot(312)
p.plot(np.imag(s),'r')
p.subplot(313)
p.plot(np.abs(s))
I have a DICOM image with a mask on. It looks like a black background with a white circle in the middle (area not covered and zeroed with the mask).
The code for which is:
import numpy as np
import dicom
import pylab
ds = dicom.read_file("C:\Users\uccadmin\Desktop\James_Phantom_CT_Dec_16th\James Phantom CT Dec 16th\Images\SEQ4Recon_3_34\IM-0268-0001.dcm")
lx, ly = ds.pixel_array.shape
X, Y = np.ogrid[0:lx, 0:ly]
mask = (X - lx/2)**2 + (Y - ly/2)**2 > lx*ly/8 # defining mask
ds.pixel_array[mask] = 0
print np.std(ds.pixel_array) # trying to get standard deviation
pylab.imshow(ds.pixel_array, cmap=pylab.cm.bone) # shows image with mask
I want to get the standard deviation of the pixel values INSIDE the white circle ONLY i.e. exclude the black space outside the circle (the mask).
I do not think the value I am getting with the above code is correct, as it is ~500, and the white circle is almost homogenous.
Any ideas how to make sure that I get the standard deviation of the pixel values within the white circle ONLY in a Pythonic way?
I think the reason you are getting a big number is because your standard deviation is including all the zero values.
Is it enough for you to simply ignore all zero values? (This will be okay, providing that no or very few pixels in the circle have value 0.) If so
np.std([x for x in ds.pixel_array if x > 0])
should do the trick. If this isn't good enough, then you can reverse the condition in your mask to be
mask = (X - lx/2)**2 + (Y - ly/2)**2 < lx*ly/8 # defining mask, < instead of >
and do
mp.std(ds.pixel_array[mask])