qtruby draw picture point by point - ruby

Hi I'm trying to write BMP reader writer in ruby and now i'm stuck on write it on screen.
I have picture stored in pixels array and on every pixel is stored rgb color.
But nothing happens in in window? What I'm doing wrong? Or is there any qt object to which i can stored pixel data and simply paint it?
def initialize
super
setWindowTitle "Transparent rectangles"
resize 590, 90
move 300, 300
show
end
def paintEvent event
painter = Qt::Painter.new self
bmp = BMP::Reader.new("picture.bmp")
drawPicture(painter,bmp.getPixels())
painter.end
end
def drawPicture(painter, pixels)
painter.setPen Qt::NoPen
0.upto(pixels.length-1) do |i|
0.upto(pixels[0].length-1) do |j|
painter.setBrush Qt::Brush.new Qt::Color.new pixels[i][j][2], pixels[i][j][1], pixels[i][j][0], 255
painter.drawPoint(i,j)
end
end
end

QPainter.drawPoint uses the current pen, not the brush. Call painter.setPen before each point.
But you would be much better off storing the pixels in a QImage. Qt already has support for reading BMP files so there's no need to implement that yourself unless you have a good reason to.

Related

How do I save an image generated by imshow(image) into a variable?

This is my code. I want to save the image displayed on imshow(img) into a variable to use it later. Thanks!
img=imread('image1.bmp');
figure(1), imshow(img);
[r c]=ginput(4);
Bw=roipoly(img,r,c);
% figure,imshow(Bw)
[R C]=size(Bw);
for i=1:R
for j=1:C
if Bw(i,j)==1
img(i,j)=img(i,j);
else
img(i,j)=0;
end
end
end
figure,
imshow(img); title ('Output Image');
You can use the classic getframe / cdata idiom. With the figure window open, simply do this:
figure;
imshow(img); title('Output Image');
h = getframe;
im = h.cdata;
h is a handle to the current frame that is open, and the cdata field contains image data for the frame. The above code stores the frame image data into a variable called im for use for later.
Minor Comment
That for loop code to set the output is a bit inefficient. You can do this completely vectorized and you'll notice significant speedups.
This code:
for i=1:R
for j=1:C
if Bw(i,j)==1
img(i,j)=img(i,j);
else
img(i,j)=0;
end
end
end
... can be replaced with:
img(~BW) = 0;
I also don't understand why you'd need to store the image data inside the frame of imshow... when img already contains your data and you are ultimately showing the data contained in img. Why can't you just use img directly for your application? Nevertheless, the above solution will work.

how to scale image by percentage by carrierwave

I want to generate images in 25%, 50%, 75% size from original image, but seems carrierwave's resize_to_fill/fit not support percentage. Anyone knows how to do like this?
Thanks.
After some research, i found one solution:
process :store_dimensions
version :r_3x do
process :resize_to_fit_by_percentage => 0.75
end
private
def resize_to_fit_by_percentage(percentage)
resize_to_fit model.width*percentage, nil
end
def store_dimensions
if file && model
model.width, model.height = ::MiniMagick::Image.open(file.file)[:dimensions]
end
end
Firstly get the dimension of the uploaded image, then define a custom resize method(here is resize_to_fi_by_percentage), and resize image in this method like the code does.

Writing a greyscale video using Videowriter/avifile

I am writing a function that generates a movie mimicking a particle in a fluid. The movie is coloured and I would like to generate a grayscaled movie for the start. Right now I am using avifile instead of videowriter. Any help on changing this code to get grayscale movie? Thanks in advance.
close all;
clear variables;
colormap('gray');
vidObj=avifile('movie.avi');
for i=1:N
[nx,ny]=coordinates(Lx,Ly,Nx,Ny,[x(i),-y(i)]);
[xf,yf]=ndgrid(nx,ny);
zf=zeros(size(xf))+z(i);
% generate a frame here
[E,H]=nfmie(an,bn,xf,yf,zf,rad,ns,nm,lambda,tf_flag,cc_flag);
Ecc=sqrt(real(E(:,:,1)).^2+real(E(:,:,2)).^2+real(E(:,:,3)).^2+imag(E(:,:,1)).^2+imag(E(:,:,2)).^2+imag(E(:,:,3)).^2);
clf
imagesc(nx/rad,ny/rad,Ecc);
writetif(Ecc,i);
if i==1
cl=caxis;
else
caxis(cl)
end
axis image;
axis off;
frame=getframe(gca);
cdata_size = size(frame.cdata);
data = uint8(zeros(ceil(cdata_size(1)/4)*4,ceil(cdata_size(2)/4)*4,3));
data(1:cdata_size(1),1:cdata_size(2),1:cdata_size(3)) = [frame.cdata];
frame.cdata = data;
vidObj = addframe(vidObj,frame);
end
vidObj = close(vidObj);
For your frame data, use rgb2gray to convert a colour frame into its grayscale counterpart. As such, change this line:
data(1:cdata_size(1),1:cdata_size(2),1:cdata_size(3)) = [frame.cdata];
To these two lines:
frameGray = rgb2gray(frame.cdata);
data(1:cdata_size(1),1:cdata_size(2),1:cdata_size(3)) = ...
cat(3,frameGray,frameGray,frameGray);
The first line of the new code will convert your colour frame into a single channel grayscale image. In colour, grayscale images have all of the same values for all of the channels, which is why for the second line, cat(3,frameGray,frameGray,frameGray); is being called. This stacks three copies of the grayscale image on top of each other as a 3D matrix and you can then write this frame to your file.
You need to do this stacking because when writing a frame to file using VideoWriter, the frame must be colour (a.k.a. a 3D matrix). As such, the only workaround you have if you want to write a grayscale frame to the file is to replicate the grayscale image into each of the red, green and blue channels to create its colour equivalent.
BTW, cdata_size(3) will always be 3, as getframe's cdata structure always returns a 3D matrix.
Good luck!

Rails + Carrierwave + RMagick : Crop only if image is large

I am using carrier-wave to upload images. On upload I am creating thumbnails for the image which is done using Rmagick method, resize_to_fill like below.
version :thumb do
process :resize_to_fill=> [150, 150]
end
Here is output of all the RMagick methods carrierwave supports (none of which I want):
:resize_to_fill => [150,150]
This works fine on larger images but my smaller images are enlarged to 150 x 150.
:resize_to_fit => [150,150]
Again it was resized, I want it left alone!
:resize_to_limit => [150,150]
This one leaves it as is, but larger images are not cropped. They are resized to keep the aspect ratio.
Here is the result I want and how my small and larger images should look.
How do this? I want smaller images to be left alone and crop only larger images to 150 x 150. Is there another method or options I can pass to resize_to_fill?
I solved it by modifying :resize_to_fill carrierwave method as described in their code here.
I just made a new method with the same code with a check to see if the uploaded image is smaller. Here is the new method:
def resize_to_fill_modfied(width, height, gravity=::Magick::CenterGravity)
manipulate! do |img|
img.crop_resized!(width, height, gravity) unless (img.columns <= width && img.rows <= height)
img = yield(img) if block_given?
img
end
end
Does exactly what I want now.

How do I capture the screen using Ruby?

I need to capture the screen using Ruby, and then get an array of RGB pixel values for each pixel on the screen.
I tried the Windows API, and can bitblt the screen and retrieve the handle of the bitmap, but I have no idea how to access the raw RGB values within this handle's data.
This is what I have at the moment, and it's fast enough, but I need to get the RGB values from the hbitmap into an array that I can work with.
Anything as fast as Bitblt but easier would be appreciated too.
def getscreen()
width = Win32API.new("User32.dll","GetSystemMetrics",["L"],"L").call(0)
height = Win32API.new("User32.dll","GetSystemMetrics",["L"],"L").call(1)
#Get desktop DC, create a compatible dc, create a comaptible bitmap and select into compatible dc.
hddc = Win32API.new("User32.dll","GetDC",["L"],"L").call(Win32API.new("User32.dll","GetDesktopWindow",[],"L").call)
hcdc = Win32API.new("Gdi32.dll","CreateCompatibleDC",["L"],"L").call(hddc)
hbitmap = Win32API.new("Gdi32.dll","CreateCompatibleBitmap",["L","L","L"],"L").call(hddc,width,height)
Win32API.new("Gdi32.dll","SelectObject",["L","L"],"L").call(hcdc,hbitmap)
Win32API.new("Gdi32.dll","BitBlt",["L","L","L","L","L","L","L","L","P"],"L").call(hcdc,0,0,width,height,hddc,0,0,"SRCCOPY|CAPTUREBLT")
#save hbitmap to stream of byte as you mentioned
puts hbitmap
#
Win32API.new("User32.dll","ReleaseDC",["L","L"],"L").call(Win32API.new("User32.dll","GetDesktopWindow",[],"L").call,hddc)
Win32API.new("Gdi32.dll","DeleteDC",["L"],"L").call(hcdc)
Win32API.new("Gdi32.dll","DeleteObject",["L"],"L").call(hbitmap)
#Print screen width and height
puts "Screen width: #{width}"
puts "Screen height: #{height}"
end
I figured out how to do this so I though I would post the solution for others who may need help.
The GetDIBits Win32API function can be used to access the RGB array stored in the bitmap captured using the above code.
http://msdn.microsoft.com/en-us/library/dd144879%28v=vs.85%29.aspx

Resources