How to crop image using opencv-ruby gem? - ruby-on-rails

I wish to crop an image using the opencv-ruby gem, how can I do this?

If you just want to crop and resize you should probably use the rmagic gem instead (https://github.com/rmagick/rmagick, docs: http://studio.imagemagick.org/RMagick/doc/).
# note the .first, since read returns an array of layers/images
image = Magick::Image::read("my_file.jpg").first
cropped_image = image.crop(x_start, y_start, width, height, true);
cropped_image.write("my_file_cropped.jpg")
If you must use OpenCV, then this should get you there or close
image = IplImage::load("my_file.jpg")
sub = image.sub_rect(x,y, width, height)
sub.save_image("my_file_cropped.jpg")

Related

problem with the 2d interpolation method using scipy.ndimage.zoom

I have an image which is in gray scale.
I wanted to upsamle the image, so I used the following code,
img = cv2.imread('unnamed.jpg')
img_1 = scipy.ndimage.zoom(img,3, order=1)
print(img.shape, img_1.shape)
and the output is
(187, 250, 3) (561, 750, 9)
For some reason, I cannot use plt.imshow(img_1) as it gives error,
TypeError: Invalid shape (561, 750, 9) for image data
I'd appreciate it if somebody could help me with it.
It looks like your image has 3 channels, which means it is not in grayscale. So, either convert it to grayscale first, and apply zoom, or, in case you want to keep the image in color mode, don't apply zoom on the image channels, because it does not make much sense.
# 1st option returns grayscale image
img = cv2.imread('unnamed.jpg',0) # returns grayscale image
img_1 = scipy.ndimage.zoom(img,3, order=1)
# 2nd option returns BGR image
img = cv2.imread('unnamed.jpg',1) # returns RGB image
img_1 = scipy.ndimage.zoom(img,[3,3,1], order=1) # zoom should contain one value for each axis.

Generate QR codes with a logo or having background colors in Ruby

I'm using rQrCode for generating QR Codes in Ruby. But I want to change the background colors or add an image in the middle of that generated QR Codes. I did some research but found nothing.
Have anyone implemented it in Ruby yet? Or do you have any idea about it?
Thanks a lot.
I'm using rQrCode for generating QR Codes in Ruby. But I want to change the background colors [...]
Reviewing the rQrCode documentation you change the fill colour of QR codes using the following :color options when creating the QR code as either an image, ANSI, SVG or HTML table, as follows:
require "rqrcode"
qrcode = RQRCode::QRCode.new("http://stackoverflow.com/questions/42691235/generate-qr-codes-with-a-logo-or-having-background-colors-in-ruby")
image = qrcode.as_png(color: "000")
svg = qrcode.as_svg(color: "000")
html = qrcode.as_html # `td.black { border-color: #000; }` in stylesheet
string = qrcode.as_ansi(dark: "\033[40m")
You can also change the background colour, use the fill option instead
qrcode = RQRCode::QRCode.new("http://stackoverflow.com/questions/42691235/generate-qr-codes-with-a-logo-or-having-background-colors-in-ruby")
image = qrcode.as_png(fill: "000")
svg = qrcode.as_svg(fill: "000")
html = qrcode.as_html # `table { background-color: #000; }` in stylesheet
string = qrcode.as_ansi(light: "\033[40m")
These can either be used together or alone, its up to you.
However, I will warn you that depending on the contrast of the colours used, it may not be able readable by your, or someone else's, QR scanner. Also, change the QR code black squares to a different colour can break the QR code or not be register by the scanner.
As for appending or merging an image
[...] or add an image in the middle of that generated QR Codes.
Generate your QR code as before and give it a Transparent background colour
# require "chunky_png" # this already required by `rqrcode`
require "rqrcode"
qrcode = RQRCode::QRCode.new("http://stackoverflow.com/questions/42691235/generate-qr-codes-with-a-logo-or-having-background-colors-in-ruby")
TRANSPARENT = ::ChunkyPNG::Color::TRANSPARENT
qr_image = qrcode.as_png(fill: TRANSPARENT, module_px_size: 4)
_ You can ignore the module_px_size: 4 option, it was useful in my following example._
Then load your logo as a separate image and compose a new image with a reasonable width & height offset; I center the known smaller image within the larger image
logo = ChunkyPNG::Image.from_file("logo.png")
height = (logo.dimension.height / 2).floor - (qr_image.dimension.height / 2).floor
width = (logo.dimension.width / 2).floor - (qr_image.dimension.width / 2).floor
qr_composed = logo.compose(qr_image, width, height)
qr_composed.save("qr_composed.png")
I have omitted logic to determine which is the large image before composing them, otherwise you will likely in encounter an out of bounds error, like so
~/gems/2.3.0/gems/chunky_png-1.3.8/lib/chunky_png/canvas/operations.rb:393:in `check_size_constraints!': Background image width is too small! (ChunkyPNG::OutOfBounds)
However, you can create a new blank image and merge the logo & QR code images either horizontally; e.g.
new_width = logo.dimension.width + qr_image.dimension.width
qr_merged_horizontally = ChunkyPNG::Image.new(new_width, logo.dimension.height, ::ChunkyPNG::Color::WHITE)
qr_merged_horizontally.compose!(logo, 0, 0)
qr_merged_horizontally.compose!(qr_image, logo.dimension.width)
qr_merged_horizontally.save("qr_merged_horizontally.png")
Or vertically; e.g.
new_height = logo.dimension.height + qr_image.dimension.height
qr_merged_vertically = ChunkyPNG::Image.new(logo.dimension.width, new_height, ::ChunkyPNG::Color::WHITE)
qr_merged_vertically.compose!(logo, 0, 0)
qr_merged_vertically.compose!(qr_image, 0, logo.dimension.height)
qr_merged_vertically.save("qr_merged_vertically.png")
By combining their widths or heights respectively.
Otherwise, it will require more external information or manual manipulation to position the images amongst one another.
References:
File: README — Documentation for rqrcode (0.10.1)
Module: ChunkyPNG::Color — Documentation for chunky_png (1.2.0)
You can overlay any image in the middle as long as it covers less area than the QR code error correction level. It's pretty simple to do with the current version of RQRCode (2.0.0):
qr_code = RQRCode::QRCode.new("some data", level: :h)
qr_code_png = qr_code.as_png(size: 600)
logo = ChunkyPNG::Image.from_file('some/path/logo.png')
qr_code_png.compose!(logo, 200, 200) # adjust the coordinates according to the logo size
qr_code_png.to_blob # binary file result

RMagick - how to create a thumbnail with an automatic height?

I am using RMagick for creating thumbnails like this:
img = Magick::Image.read(image_url).first
target = Magick::Image.new(110, 110) do
self.background_color = 'white'
end
img.resize_to_fit!(110, 110)
target.composite(img, Magick::CenterGravity, Magick::CopyCompositeOp).write(thumb_path)
This works well - I'll load the current image, create a "space" for the new thumb and then will place it there.
However, I would need to create a thumb where would be the width 110px and the height would be automatically counted... How to do this?
Thank you
You'd rather use resize_to_fill!
Doc here
image = Magick::Image.read(image_url).first
image.format = "JPG"
image.change_geometry!("110X110") { |cols, rows| image.thumbnail! cols, rows }
image.write("<path to save thumbnail>")
This turns out to be super easy! ImageMagick and GraphicsMagick both maintain aspect ratios properly, so in your case, just give the max width you want the image to be. See http://www.imagemagick.org/script/command-line-processing.php#geometry to learn more about the magick dimension operators.
If you find that you're ruby process' RAM consumption is growing, you may want to switch to an external-exec image library, like https://github.com/mceachen/micro_magick. Also, switching to GraphicsMagick is an all-around win, BTW, giving better image encoding and in less time.
require 'micro_magick'
img = MicroMagick::Convert.new("input.png")
img.resize("110") # this restricts to width, if you want to restrict to height, use "x345"
img.unsharp(1.5) # This runs an "unsharp mask" convolution filter, and is optional
img.write("output.png")

Can I apply a mask on an image with Ruby?

I have a Rails app where users can upload images. After they upload an image, I need to apply a mask on that image, so parts of it become transparant. Is this possible?
RMagick (a Ruby image manipulation library) allows you to apply clipping path on objects : http://www.imagemagick.org/RMagick/doc/rvgclip.html
Basically, you'll need to :
create a clipping path instance
use the drawing API to draw your mask
apply the path to your image
A click on the keyhole image" there pops up an example of how to achieve this :
require 'rvg/rvg'
hat = Magick::Image.read('images/Flower_Hat.jpg').first
rvg = Magick::RVG.new(hat.columns, hat.rows) do |canvas|
keyhole = Magick::RVG::ClipPath.new do |path|
path.circle(60, canvas.width/2, 80)
path.polygon(canvas.width/2-10, 60, 40, 230, 160, 230, canvas.width/2+10, 60)
end
canvas.image(hat, nil, nil, 20, 20).styles(:clip_path=>keyhole)
end
rvg.draw.write('rvg_clippath.gif')
EDIT :
If you need to apply a transparent background the simplest approach should be to crop your image, then use the Image#composite! method to add a trnasparent layer.

RMagick changing image extents with gravity

I've got an image that i'd like to 'pad' with white space and centre.
In most cases I need to resize the image from 16 or 32 pixels up to 32 pixels.
If the image is 16 pixels, I want to add 8px of white space on each side, making it a 32 pixel image (with the original floating in the middle).
If it's a 32 pixel image, then nothing changes.
I'm using RMagick to do the conversion:
image.change_geometry!("#{size}x#{size}") { |cols, rows, img|
newimg = img.extent(cols, rows)
newimg.write("#{RAILS_ROOT}#{path}/#{name}.png")
}
Which is working OK, but the smaller images are in the top left of the new image, not centred.
I was looking at the gravity setting, it seems to be what I need, but I can't work out how to specify it in the call?
Thanks in advance.
Check the implementation of the following carrierwave function
http://rubydoc.info/gems/carrierwave/0.5.1/CarrierWave/RMagick#resize_and_pad-instance_method
This is a version of the above method by using only RMagick dependency
require 'RMagick'
include Magick
module Converter
def self.resize_and_pad(img, new_img_path, width, height, background=:transparent, gravity=::Magick::CenterGravity)
img.resize_to_fit!(width, height)
new_img = ::Magick::Image.new(width, height)
if background == :transparent
filled = new_img.matte_floodfill(1, 1)
else
filled = new_img.color_floodfill(1, 1, ::Magick::Pixel.from_color(background))
end
# destroy_image(new_img)
filled.composite!(img, gravity, ::Magick::OverCompositeOp)
# destroy_image(img)
# filled = yield(filled) if block_given?
# filled
filled.write new_img_path
end
end
The extent() method takes two more parameters, x & y offsets, which is where the image will be placed within the extent. If you're asking extent for a 100x100 image, for example, and your original is only 50x50, you'd do img.extent(100, 100, 25, 25) -- which would set the image to start at offset 25,25 (thus centering it).
NOTE: There's some issue with extent expecting to use negative offset values (in which case you'd want to do -25, -25) -- check this:
why is the behavior of extent (imagemagick) not uniform across my machines?

Resources