OpenCV - Removing the independent short line in an image - image

How do I remove the short and disconnected line but retain all the other connected lines in the following image?

If you image is always this well connected, you can select the components based on their size. My code in Python (might be a simpler way, but that's how I do it) :
#get all connected components in the image with their stats (including their size, in pixel)
nb_edges, output, stats, _ = cv2.connectedComponentsWithStats(img, connectivity=8)
#output is an image where every component has a different value
size=stats[1:,-1] #extracting the size from the statistics
#selecting bigger components
for e in range(0,nb_edges-1):
#replace this line depending on your application, here I chose to keep
#all components above the mean size of components in the image
if size[e]>=np.mean(size):
th_up = e + 2
th_do = th_up
#masking to keep only the components which meet the condition
mask = cv2.inRange(output, th_do, th_up)
result = cv2.bitwise_xor(original_img, mask)

Related

Control brightness in Windows at software Level

It might be possible for a similar question to be already present on the site, but I have searched a lot and didn't find any relevant solution, so I'm posting it here.
I'm making a Night Light Application, which has two options-
Lessen the Brightness of the PC
Apply a Blue light filter mask over the screen.
I'm making this app cross platform, so I've already found a solution for Linux Systems, where I've been making use of xrandr utility to adjust the brightness and gamma at the software level, and my app works flawlessly.
The main problem is for Windows systems, where the brightness feature is only available for portable screens such as for a Laptop.
I cannot find any solution for this.
I made use of Qt5 for making a translucent app window which works good, but doesn't meet the requirement because the things displayed at kernel level are not masked like the cursor, taskbar, start menu, action center, and lots of other.
I searched a lot and lot, which included Microsoft Developer Network, where documentation included the Win32 API where brightness feature was present, but it didn't work for me, as I had a Desktop PC.
So my main problem is, How can I ajust the brightness of all Windows PC, including Laptops, Desktops n all others.
I'm working on Python with ctypes module.
I'm not that much familiar with VC+ and I cannot even afford to install it on my system as it is too much storage and resource intensive.
I primarily want to modify the output going to the physical monitor, that is to modify the Gamma values to get appropriate brightness and Yellow tincture.
I got something called gdi32.dll which deals with the outputs to screens, but I cannot find a way out as everything on the Internet is alongside C++.
Also, I cannot even provide my try code, as I'm not that much familiar to C type coding in Python.
Also, the thing I want to do, Intel Graphics Command Center already does it on my desktop.
If it can do it on at a software level, then I know its possible programmatically.
Can anyone tell is this possible what I'm thinking, and if yes, how can I achieve this?
I don't want the source code, I just want the way out for that.
Maybe GammaRamp from the Gdi32 API can be used, but I don't know how to begin.
This is a thread which actually asked this, but I didn't get my answer from here, and newbies are restricted from commenting, so I didn't have any choice than to post this question here.
I have found the way for the problem.
We can use GetDeviceGammaRamp and SetDeviceGammaRamp from the gdi32.dll library in Windows OS to set the brightness level.
To call these functions through Python, we can use ctypes module.
Below is the sample code that can set brightness of in Windows 10 via Python.
import ctypes
def displayGammaValues(lpRamp):
"""
Displays the GammaArray of 256 values of R,G,B individually
:param lpRamp: GammaArray
:return: None
"""
print("R values: ", end=' ')
for j in range(256):
print(lpRamp[0][j], end=' ')
print()
print("G values: ", end=' ')
for j in range(256):
print(lpRamp[0][j], end=' ')
print()
print("B values: ", end=' ')
for j in range(256):
print(lpRamp[0][j], end=' ')
print(), print()
def changeGammaValues(lpRamp, brightness):
"""
Modifies the Gamma Values array according to specified 'Brightness' value
To reset the gamma values to default, call this method with 'Brightness' as 128
:param lpRamp: GammaArray
:param brightness: Value of brightness between 0-255
:return: Modified GammaValue Array
"""
for i in range(256):
iValue = i * (brightness + 128)
if iValue > 65535: iValue = 65535
lpRamp[0][i] = lpRamp[1][i] = lpRamp[2][i] = iValue
return lpRamp
if __name__ == '__main__':
brightness = 100 # can be aby value in 0-255 (as per my system)
GetDC = ctypes.windll.user32.GetDC
ReleaseDC = ctypes.windll.user32.ReleaseDC
SetDeviceGammaRamp = ctypes.windll.gdi32.SetDeviceGammaRamp
GetDeviceGammaRamp = ctypes.windll.gdi32.GetDeviceGammaRamp
hdc = ctypes.wintypes.HDC(GetDC(None))
if hdc:
GammaArray = ((ctypes.wintypes.WORD * 256) * 3)()
if GetDeviceGammaRamp(hdc, ctypes.byref(GammaArray)):
print("Current Gamma Ramp Values are:")
displayGammaValues(GammaArray)
GammaArray = changeGammaValues(GammaArray, brightness)
print("New Current Gamma Ramp Values are:")
displayGammaValues(GammaArray)
if SetDeviceGammaRamp(hdc, ctypes.byref(GammaArray)): print("Values set successfully!")
else: print("Unable to set GammaRamp")
if ReleaseDC(hdc): print("HDC released")
else: print("HDC not found")
This sets the brightness value, that's between 0-255. Values may differ system-to-system, so preferable range for brightness is 0 - 128 where 128 is the default brightness.
FYI windows already has a monitor blue shade/color shift built in. Dimming external monitor outputs on a desktop is likely not possible.
You'll need to hook into the windows API somehow to control windows functions. There's some documentation about adjusting color temperature (making that warmer would essentially add a "blue light" filter to a screen on microsoft's website.
https://learn.microsoft.com/en-us/windows/win32/api/highlevelmonitorconfigurationapi/nf-highlevelmonitorconfigurationapi-setmonitorcolortemperature.
In terms of executing a small CPP script that actually can interface with windows, you can write a small CPP program, then compile it and execute from python using (slightly modified from this question)
import os
import subprocess
for filename in os.listdir(os.getcwd()):
proc = subprocess.Popen(["./prog", filename])
proc.wait()
However if you don't have the room to install visual studio compile tools, you won't be able to compile a small CPP script locally. There are a few online services that would be able to do that for you though.

Creating an image datastore from the images already loaded in the memory

I was working with the The Street View House Numbers (SVHN) Dataset and primarily with the train_32x32.mat file given. Loading the file as:
load train_32x32.mat
loads 2 variables X and y in the workspace.
The dimensions of each X and y are 32 x 32 x 3 x 73257 and 73257 x 1 respectively. I am used to creating an imageDatastore and then using augmentedImageDatastore to put some form of pre-processing before attempting to create a CNN.
But now since X already contains the image pixels for 73257 images, is there a way I could still create an imageDatastore? For what I could make through the documentation of imageDatstore, it only accepts the physical location of the image directory.
It doesn't look like there is a way unless I save them to disk files first.
May be I could then delete those files when my program exits.

What's the best technique for comparing images' similarity?

I have an image master.png and more than 10.000 of other images (slave_1.png, slave_2.png, ...). They all have:
The same dimensions (Eg. 100x50 pixels)
The same format (png)
The same image background
98% of the slaves are identical to the master, but 2% of the slaves have a slightly different content:
New colors appear
New small shapes appear in the middle of the image
I need to spot those different slaves. I'm using Ruby, but I have no problem in use a different technology.
I tried to File.binread both images and then compare using ==. It worked for 80% of the slaves. In other slaves, it was spotting changes but the images was visually identical. So it doesn't work.
Alternatives are:
Count the number of colors present in each slave and compare with master. It will work in 100% of the time. But I don't know how to do it in Ruby in a "light" way.
Use some image processor to compare by histograms like RMagick or ruby-vips8. This way should also work but I need to consume the less CPU/Memory possible.
Write a C++/Go/Crystal program to read pixel by pixel and return a number of colors. I think in this way we can get performance out of if. But for sure is the hard way.
Any enlightenment? Suggestions?
In ruby-vips, you could do it like this:
#!/usr/bin/ruby
require 'vips'
# find normalised histogram of reference image
ref = Vips::Image.new_from_file ARGV[0], access: :sequential
ref_hist = ref.hist_find.hist_norm
ARGV[1..-1].each do |filename|
# find sample hist
sample = Vips::Image.new_from_file filename, access: :sequential
sample_hist = sample.hist_find.hist_norm
# calculate sum of squares of differences; if it's over a threshold, print
# the filename
diff_hist = (ref_hist - sample_hist) ** 2
diff = diff_hist.avg * diff_hist.width * diff_hist.height
if diff > 100
puts "#{filename}, #{diff}"
end
end
If I make some test data:
$ vips crop ~/pics/k2.jpg ref.png 0 0 100 50
$ for i in {1..10000}; do cp ref.png $i.png; done
I can run it like this:
$ time ../similarity.rb ref.png *.png
real 0m55.974s
user 1m31.921s
sys 0m54.433s
It runs in a steady ~80mb of memory.

MATLAB : access loaded MAT file very slow

I'm currently working on a project involving saving/loading quite big MAT files (around 150 MB), and I realized that it was much slower to access a loaded cell array than the equivalent version created inside a script or a function.
I created this example to simulate my code and show the difference :
clear; clc;
disp('Test for computing with loading');
if exist('data.mat', 'file')
delete('data.mat');
end
n_tests = 10000;
data = {};
for i=1:n_tests
data{end+1} = rand(1, 4096);
end
% disp('Saving data');
% save('data.mat', 'data');
% clear('data');
%
% disp('Loading data');
% load('data.mat', '-mat');
for i=1:n_tests
tic;
for j=1:n_tests
d = sum((data{i} - data{j}) .^ 2);
end
time = toc;
disp(['#' num2str(i) ' computed in ' num2str(time) ' s']);
end
In this code, no MAT file is saved nor loaded. The average time for one iteration over i is 0.75s. When I uncomment the lines to save/load the file, the computation for one iteration over i takes about 6.2s (the saving/loading time is not taking into consideration). The difference is 8x slower !
I'm using MATLAB 7.12.0 (R2011a) 64 bits with Windows 7 64 bits, and the MAT files are saved with the version v7.3.
Can it be related to the compression of the MAT file? Or caching variables ?
Is there any way to prevent/avoid this ?
I also know this problem. I think it's also related to the inefficient managing of memory in matlab - and as I remember it's not doing well with swapping.
A 150MB file can easily hold a lot of data - maybe more than can be quickly allocated.
I just made a quick calculation for your example using the information by mathworks
In your case total_size = n_tests*121 + n_tests*(1*4096* 8) is about 313MB.
First I would suggest to save them in format 7 (instead of 7.3) - I noticed very poor performance in reading this new format. That alone could be the reason of your slowdown.
Personally I solved this in two ways:
Split the data in smaller sets and then use functions that load the data when needed or create it on the fly (can be elegantly done with classes)
Move the data into a database. SQLite and MySQL are great. Both work efficiently with MUCH larger datasets (in the TBs instead of GBs). And the SQL language is quite efficient to quickly get subsets to manipulate.
I test this code with Windows 64bit, matlab 64bit 2014b.
Without saving and loading, the computation is around 0.22s,
Save the data file with '-v7' and then load, the computation is around 0.2s.
Save the data file with '-v7.3' and then load, the computation is around 4.1s.
So it is related to the compression of the MAT file.

How do I Acquire Images at Timed Intervals using MATLAB?

I'm a MATLAB beginner and I would like to know how I can acquire and save 20 images at 5 second intervals from my camera. Thank you very much.
First construct a video input interface
vid = videoinput('winvideo',1,'RGB24_400x300');
You'll need to adjust the last bit for your webcam. To find a list of webcam devices (and other things besides) use:
imaqhwinfo
The following makes the first webcam into an object
a=imaqhwinfo('winvideo',1)
Find the list of supported video formats with
a.SupportedFormats
You'll then want to start up the interface:
start(vid);
preview(vid);
Now you can do the following:
pics=cell(1,20)
for i=1:20
pause(5);
pics{i}=getsnapshot(vid);
end
Or, as other commentators have noted, you could also use a Matlab timer for the interval.
If you wish to capture images with a considerably shorter interval (1 or more per second), it may be more useful to consider the webcam as a video source. I've left an answer to this question which lays out methods for achieving that.
There are several ways to go about this, each with advantages and disadvantages. Based on the information that you've posted so far, here is how I would do this:
vid = videoinput('dcam', 1'); % Change for your hardware of course.
vid.FramesPerTrigger = 20;
vid.TriggerRepeat = inf;
triggerconfig(vid, 'manual');
vid.TimerFcn = 'trigger(vid)';
vid.TimerPeriod = 5;
start(vid);
This will acquire 20 images every five seconds until you call STOP. You can change the TriggerRepeat parameter to change how many times acquisition will occur.
This obviously doesn't do any processing on the images after they are acquired.
Here is a quick tutorial on getting one image http://www.mathworks.com/products/imaq/description5.html Have you gotten this kind of thing to work yet?
EDIT:
Now that you can get one image, you want to get twenty. A timer object or a simple for loop is what you are going to need.
Simple timer object example
Video example of timers in MATLAB
Be sure to set the "tasks to execute" field to twenty. Also, you should wrap up all the code you have for one picture snap into a single function.
To acquire the image, does the camera comes with some documented way to control it from a computer? MATLAB supports linking to outside libraries. Or you can buy the appropriate MATLAB toolbox as suggested by MatlabDoug.
To save the image, IMWRITE is probably the easiest option.
To repeat the action, a simple FOR loop with a PAUSE will give you roughly what you want with very little work:
for ctr = 1:20
img = AcquireImage(); % your function goes here
fname = ['Image' num2str(ctr)]; % make a file name
imwrite(img, fname, 'TIFF');
pause(5); % or whatever number suits your needs
end
If, however, you need exact 5 second intervals, you'll have to dive into TIMERs. Here's a simple example:
function AcquireAndSave
persistent FileNum;
if isempty(FileNum)
FileNum = 1;
end
img = AcquireImage();
fname = ['Image' num2str(FileNum)];
imwrite(img, fname, 'TIFF');
disp(['Just saved image ' fname]);
FileNum = FileNum + 1;
end
>> t = timer('TimerFcn', 'ShowTime', 'Period', 5.0, 'ExecutionMode', 'fixedRate');
>> start(t);
...you should see the disp line from AcquireAndSave repeat every 5 seconds...
>> stop(t);
>> delete(t);

Resources