Marker and figure size in matplotlib : not sure how it works - python-2.7

I want to make a figure that marker's size depend on the size of the figure. That way, using square marker size, no matter what resolution or figure size you choose, all the markers will touch each other, masking the backgroud without overlapping. Here is where I am at:
The marker size is specified in pt^2, with 1pt=1/72inch, the resolution in Pixel Per Inches, and the figure size in pixels (also the proportion that main subplot represent out of the main figure size : 0.8). So, if my graph's limits are lim_min and lim_max, I should by able to get the corresponding marker size using :
marker_size=((fig_size*0.8*72/Resolution)/(lim_max-lim_min))**2
because (fig_size*0.8*72/Resolution) is the size of the figure in points, and (lim_max-lim_min) the number of marker I want to fill a line.
And that should do the trick !... Well it doesn't... At all... The marker are so small they are invisible without a zoom. And I don't get why.
I understand this my not be the best way, and the way you would do it, but I see no reason why it wouldn't work, so I want to understand where I am wrong.
PS : both my main figure and my subplot are squares
Edit :
Okay so I found the reason of the problem, not the solution. The problem in the confusion between ppi and dpi. Matplotlib set the resolution in dpi, which is defined as a unit specific to scanner or printer depending on the model (?!?).
Needless to say I am extremely confused on the actual meaning of the resolution in matplotlib. It simply makes absolutely no sens to me. Please someone help. How do i convert this to a meaningful unit ? It seems that matplotlib website is completely silent on the matter.

If you specify the figure size in inches and matplotlib uses a resolution of 72 points per inch (ppi), then for a given number of markers the width of each marker should be size_in_inches * points_per_inch / number_of_markers points (assuming for now that the subplot uses the entire figure)? As I see it, dpi is only used to display or save the figure in a size of size_in_inches * dpi pixels.
If I understand your goal correctly, the code below should reproduce the required behavior:
# Figure settings
fig_size_inch = 3
fig_ppi = 72
margin = 0.12
subplot_fraction = 1 - 2*margin
# Plot settings
lim_max = 10
lim_min = 2
n_markers = lim_max-lim_min
# Centers of each marker
xy = np.arange(lim_min+0.5, lim_max, 1)
# Size of the marker, in points^2
marker_size = (subplot_fraction * fig_size_inch * fig_ppi / n_markers)**2
fig = pl.figure(figsize=(fig_size_inch, fig_size_inch))
fig.subplots_adjust(margin, margin, 1-margin, 1-margin, 0, 0)
# Create n_markers^2 colors
cc = pl.cm.Paired(np.linspace(0,1,n_markers*n_markers))
# Plot each marker (I could/should have left out the loops...)
for i in range(n_markers):
for j in range(n_markers):
ij=i+j*n_markers
pl.scatter(xy[i], xy[j], s=marker_size, marker='s', color=cc[ij])
pl.xlim(lim_min, lim_max)
pl.ylim(lim_min, lim_max)
This is more or less the same as you wrote (in the calculation of marker_size), except the division by Resolution has been left out.
Result:
Or when settings fig_ppi incorrectly to 60:

Related

Incorrect metrics and sizes of font created by CreateFont()

I trying to render a font into bitmap using WinAPI, but I can't reach needed sizes of font.
Here's how the font is initialized:
HDC dc = ::CreateCompatibleDC(NULL);
::SetMapMode(dc, MM_TEXT);
::SetTextAlign(dc, TA_LEFT | TA_TOP | TA_UPDATECP);
int size_in_pixels = 18;
HFONT font = ::CreateFontA(-size_in_pixels, ..., "Arial");
::SelectObject(dc, font);
::TEXTMETRICW tm = { 0 };
GetTextMetricsW(dc, &tm);
But after it I getting incorrect values both in GetGlyphOutlineW and GetTextMetricsW, it's not size I passed as parameter
I know that it's expecting value in logical units, but in MM_TEXT 1 unit should be 1 pixel, don't it?
I expecting that CreateFontA accepting point size when I passing a negative value (like here https://i.stack.imgur.com/tEt8J.png), but in fact it's wrong.
I tried bruteforcing values, and find out proper parameter for a few sizes:
18px = -19; 36px = -39; 73px = -78;
Also I tried formula that provided by Microsoft:
nHeight = -MulDiv(PointSize, GetDeviceCaps(hDC, LOGPIXELSY), 72);
But it's also giving me a wrong result, rendered text (using GetGlyphOutlineW) is larger if measure it (for example height of 'j' should have exact size that I passed)
Also metrics from GetTextMetricsW are wrong, for example tmAscent. I know that on Windows it's including internal leading, but even if subtract tmInternalLeading from tmAscent it's still incorrect.
By the way, values from GetCharABCWidthsW are correct, so a+b+c is width of glyph in pixels (while documentation says it should be in logical units).
Also I should say about DPI, usually I using 125% on Windows 10 scale in settings, but I tried even with 100%, interesting that ::GetDeviceCaps(dc, LOGPIXELSY) not changing with scale I using, it's always 96
Here's example of CreateFontA(-128, ...) with final atlas and metrics:
rendered atlas
Question #1: What should I do to pass wanted point size in pixels and receive glyphs in proper size with correct metrics in pixels?
Question #2: What the strange units all these functions are using?
When you use ::SetMapMode(dc, MM_TEXT); the font size is specified in device pixels. Negative value excludes internal leading, so for the same absolute value the negative ones produce visually bigger fonts. If you want to get same height from GetTextExtentPoint32 for different fonts, use positive values.
In your example with -128 height, you are requesting font for which, after internal leading exclusion, height is 128 pixels. Font mapper selects 143 which is correct for internal leading of 15 pixels (128+15=143). tmAscent + tmDescent are also correct (115+28=143). You get what you specified.
You should take into account that values in text metric don't state hard bounds. Designer can design fonts so its glyphs sometimes go beyond guiding lines or don't reach them.
for example height of 'j' should have exact size that I passed
Dot over j can go beyond or not reach top line if designer finds it visually plausible to design it that way.
interesting that ::GetDeviceCaps(dc, LOGPIXELSY) not changing with scale I using, it's always 96
Unless you log off and log in, system DPI doesn't change. For per monitor DPI aware application you have to get DPI from monitor parameters or cache value given by WM_DPICHANGED.
Question #1: What should I do to pass wanted point size in pixels and receive glyphs in proper size with correct metrics in pixels?
I think you want to get specific distance between top and bottom lines and this is exactly how you create font HFONT font = ::CreateFontA(-size_in_pixels, ..., "Arial");. The problem lies in your assumption that font design lines are hard boundaries for each glyph, but font's designer don't have to strictly align glyphs to these lines. If you want glyphs strictly aligned, probably there is no way to get it. Maybe check different font.
Question #2: What the strange units all these functions are using?
When mode is set to WM_TEXT, raw device pixels are used. Positive height specifies height including tmInternalLeading, negative excludes it.
For positive value:
tmAscent + tmDescent = requestedHeight
For negative value:
tmAscent + tmDescent - tmInternalLeading = requestedHeight
Bellow I have pasted screen shots with different fonts showing that depending on selected font glyphs could be designed so they don't reach top line or go beyond it and bottom line in most cases also isn't reached.
Seems that for your requirements Arial Unicode MS would be better fit (but j still doesn't reach where you want it).
Arial:
Arial Unicode MS
Input Mono
Trebuched MS

OpenCV - Getting a part of an image

I want to get a part of an image loaded in another image. There are several, easy ways to do that but for example cv::Mat OutImage = Image(cv::Rect(7,47,1912,980)) but- the resulted image is to large For example:
I got an image with 1920 x 1024 pixel. I want to cut a cv:Rect(7,47,1912,980) from it. I would suggest, that the resulting image has the size (1912 - 7 = 1905) x (980 - 47 = 933) pixel but it has 1912 x 980. It seems, that Opencv is just cutting on the right lower side and keeping the left upper area.
The dimension of the image is important, because in the next step I'd like to perform a substraction which is only valid if the Mat object has the same dimension. I also don't want to use a loop designed by myself, because performance is very important.
Any ideas?
Regards,
Jan
It is actually cv:Rect(x,y,width,height), so you should set the last two parameters as your willing output width and height. Mind the range you set or it would cause errors.
I had also dealed with this issue I will just give my example here it is working for me well. You may also try this one.
Rect const box(100, 295, 400, 185); //this mean the first corner is
//(x,y)=(100,295)
// and the second corner is
//(x + b, y+c )= (100 +400,295+185)
Mat ROI = frame(box);

Disparity Map Block Matching

I am writing a disparity matching algorithm using block matching, but I am not sure how to find the corresponding pixel values in the secondary image.
Given a square window of some size, what techniques exist to find the corresponding pixels? Do I need to use feature matching algorithms or is there a simpler method, such as summing the pixel values and determining whether they are within some threshold, or perhaps converting the pixel values to binary strings where the values are either greater than or less than the center pixel?
I'm going to assume you're talking about Stereo Disparity, in which case you will likely want to use a simple Sum of Absolute Differences (read that wiki article before you continue here). You should also read this tutorial by Chris McCormick before you read more here.
side note: SAD is not the only method, but it's really common and should solve your problem.
You already have the right idea. Make windows, move windows, sum pixels, find minimums. So I'll give you what I think might help:
To start:
If you have color images, first you will want to convert them to black and white. In python you might use a simple function like this per pixel, where x is a pixel that contains RGB.
def rgb_to_bw(x):
return int(x[0]*0.299 + x[1]*0.587 + x[2]*0.114)
You will want this to be black and white to make the SAD easier to computer. If you're wondering why you don't loose significant information from this, you might be interested in learning what a Bayer Filter is. The Bayer Filter, which is typically RGGB, also explains the multiplication ratios of the Red, Green, and Blue portions of the pixel.
Calculating the SAD:
You already mentioned that you have a window of some size, which is exactly what you want to do. Let's say this window is n x n in size. You would also have some window in your left image WL and some window in your right image WR. The idea is to find the pair that has the smallest SAD.
So, for each left window pixel pl at some location in the window (x,y) you would the absolute value of difference of the right window pixel pr also located at (x,y). you would also want some running value, which is the sum of these absolute differences. In sudo code:
SAD = 0
from x = 0 to n:
from y = 0 to n:
SAD = SAD + absolute_value|pl - pr|
After you calculate the SAD for this pair of windows, WL and WR you will want to "slide" WR to a new location and calculate another SAD. You want to find the pair of WL and WR with the smallest SAD - which you can think of as being the most similar windows. In other words, the WL and WR with the smallest SAD are "matched". When you have the minimum SAD for the current WL you will "slide" WL and repeat.
Disparity is calculated by the distance between the matched WL and WR. For visualization, you can scale this distance to be between 0-255 and output that to another image. I posted 3 images below to show you this.
Typical Results:
Left Image:
Right Image:
Calculated Disparity (from the left image):
you can get test images here: http://vision.middlebury.edu/stereo/data/scenes2003/

How to make image comparison in openCV more coarse

I am writing a code on raspberry pi in python to compare two images using mean squared error. The project is an personal home security thing.
My main goal is to detect a change between the images that I capture from pi camera(if something is added to the current image or something removed from the image) but right now my code is too sensitive. It is affected by change in background lighting, which I do not want.
I have two options in front of me, to either scrape my current logic and start a new one or improve my current logic to account for these noise(if I can call them that). I am searching for ways to improve my logic but I wanted some guidance on how to go about it.
My biggest fear being, am I wasting time kicking a dead horse or should I just look for some other algorithm to detect a change in image or should I use edge detection
import numpy as np
import cv2
import os
from threading import Thread
######Function Definition########################################
def mse(imageA, imageB):
# the 'Mean Squared Error' between the two images is the
# sum of the squared difference between the two images;
# NOTE: the two images must have the same dimension
err = np.sum((imageA.astype("int") - imageB.astype("int")) ** 2)
err /= int(imageA.shape[0] * imageA.shape[1])
# return the MSE, the lower the error, the more "similar"
# the two images are
return err
def compare_images(imageA, imageB):
# compute the mean squared error
m = mse(imageA, imageB)
print(m)
def capture_image():
##shell command to click photos
os.system(image_args)
##original image Path variable
original_image_path= "/home/pi/Downloads/python-compare-two-images/originalimage.png"
##original_image_args is a shell command to click photos
original_image_args="raspistill -o "+original_image_path+" -w 320 -h 240 -q 50 -t 500"
os.system(original_image_args)
##read the greyscale of the image in to the variable original_image
original_image=cv2.imread(original_image_path, 0)
##Three images
image_args="raspistill -o /home/pi/Downloads/python-compare-two-images/Test_Images/image.png -w 320 -h 240 -q 50 --nopreview -t 10 --exposure sports"
image_path="/home/pi/Downloads/python-compare-two-images/Test_Images/"
image1_name="image.png"
#created a new thread to take pictures
My_Thread=Thread(target=capture_image)
#Thread started
My_Thread.start()
flag = 0
while(True):
if(My_Thread.isAlive()==True):
flag=0
else:
flag=1
if(flag==1):
flag=0
image1 = cv2.imread((image_path+image1_name), 0)
My_Thread=Thread(target=capture_image)
My_Thread.start()
compare_images(original_image, image1)
A first improvement is to adjust a gain to compensate for the global variation of the light. Like taking the average intensity of the two images and correcting one with the ratio of the intensities.
This can fail in case of an change of the foreground, which will influence the global average. If that change in the foreground doesn't have a too large area, you can get an estimate by robust fitting of a linear model y = a.x.
A worse, but unfortunately common, scenario, is when the background illumination changes in a non-uniform way. A partial solution is to try and fit a non-uniform gain model such as one obtained by bilinear interpolation between gains estimated at the corners, or a finer subdivision of the image.
The topic of change detection is a very studied field. One of the basic options is to model each one of the pixels as a Gaussian distribution by sampling a lot of images for each pixel and calculate the mean and variance of each pixel.
For the pixels that tend to change when there is change in lighting the variance of the pixels will be bigger than the ones that don't change as much.
In order to detect movement for a certain pixel you just need to choose what is the probability you consider as an unordarinry change in the pixel value and use the Gaussain distribution you calculated to find what is the corresponding value that is considered unordarinry.
To make this solution efficient for your raspberry pi you will need to first do an "offline" calculation of the values for each pixel that will be the threshold values for which the change in the pixel value is considered movement and store them in a file and than in the "online" sage you will just compare each pixel to the calculated value.
For the "offline" stage i recommend using images that were recorder during the entire day in order to get all the variation you need per pixel. This stage of curse can be done on your computer and only the output file will be uploaded to the raspberry pi

Subtract displaced mask using OpenCV

I want to do:
masked = image - mask
But I want to "displace" mask. That is, move it vertically and horizontally (as long as the intersection between it and image is not empty, this would be valid).
I have some hand-coded assembly (which uses MMX instructions) which does this, embedded in a C++ program, but it's unstable when doing vertical displacement, so I thought of using OpenCV instead. Would it be possible to do this calling only one OpenCV function?
Performance is critical; using OpenCV, time should be at least in the same order of magnitude as the assembly code.
EDIT: Here's an example
image (medium frame, see the contrast in the guy's skull):
mask (first frame, no contrast):
image - mask, without displacement. Notice how the contrast path is enhanced, but since the patient moved a little, we can see some skull contours which are visual noise for diagnostic purposes.
image - mask, mask displaced about 5 pixels down. To try and compensate for the noise introduced by the patient's movement, we "displace" the mask slightly so as to remove the contours and see the contrast path better (brightness and contrast were adjusted, that's why it looks a bit darker).
EDIT 2: About the algorithm, I managed to fix its issues. It doesn't crash anymore, but the downside is that it now processes all image pixels (it should only process those which need to be subtracted). Anyway, how to fix the old code is not my question; my question is, how do I do this processing using OpenCV? I'll post some profiling results later.
I know this is in Python, so not what you are after, but translating it to C++ should be very straight forward. It crops both images to matching sizes (required for nearly all operations), determined by the displacement between the images, and their relative sizes. This method should be quick, as cv.GetSubRect doesn't copy anything, so its just down to the cv.AbsDiff function (if you have an actual difference mask, you could use cv.Sub which should make it even quicker). Also this code will handle displacement in any direction and mask and image can be any size (mask can be larger than image). There must be an overlap for a specified displacement. The difference between images can be viewed alone, or the difference 'in-place'.
A nice diagram to illustrate whats going on. The first two squares are example image and mask. The next three squares show a horizontal displacement of the 'mask' of -30, 0, and 30 pixels, and the last one has a displacement of 20, 20.
import cv
image = cv.LoadImageM("image.png")
mask = cv.LoadImageM("mask.png")
image = cv.LoadImageM("image2.png")
mask = cv.LoadImageM("small_mask.png")
image_width, image_height = cv.GetSize(image)
mask_width, mask_height = cv.GetSize(mask)
#displacements here:
horiz_disp = 20
vert_disp = 20
image_horiz = mask_horiz = image_vert = mask_vert = 0
if vert_disp < 0:
mask_vert = abs(vert_disp)
sub_height = min(mask_height + vert_disp, image_height)
else:
sub_height = min(mask_height, image_height - vert_disp)
image_vert = vert_disp
if horiz_disp < 0:
mask_horiz = abs(horiz_disp)
sub_width = min(mask_width + horiz_disp, image_width)
else:
sub_width = min(mask_width, image_width - horiz_disp)
image_horiz = horiz_disp
#cv.GetSubRect returns a rectangular part of an image, without copying any data. - fast.
mask_sub = cv.GetSubRect(mask, (mask_horiz, mask_vert, sub_width, sub_height))
image_sub = cv.GetSubRect(image, (image_horiz, image_vert, sub_width, sub_height))
#Subtracts the mask overlap region from the image overlap region, puts it in image_sub
cv.AbsDiff(image_sub, mask_sub, image_sub)
# Shows diff only:
cv.ShowImage('image_sub', image_sub)
# Shows image with diff section
cv.ShowImage('image', image)
cv.WaitKey(0)