Carrierwave/Minimagick - Cropping is always inaccurate, except when 'y' parameter is 0 - ruby-on-rails-3

Having implemented the ability to crop as shown in the Railscasts episode 182 (revised), I can't seem to get cropping work accurately. What is cropped is always the top 20% of the area selected in the crop. Except when the 'y' parameter is 0, that is when the cropping area is touching the top of the image. Then cropping works fine.
My implementation is the same as shown in the screencast, except that I am calling the crop_avatar method from the controller like this:
#profile.crop_x = params[:profile][:crop_x]
#profile.crop_y = params[:profile][:crop_y]
#profile.crop_h = params[:profile][:crop_y]
#profile.crop_w = params[:profile][:crop_w]
#profile.crop_avatar
#profile.save!
Also the crop method in avatar_uploader is implemented like this:
def crop
if model.crop_x.present?
resize_to_limit(500, 500)
manipulate! do |img|
x = model.crop_x
y = model.crop_y
w = model.crop_w
h = model.crop_h
img.crop "#{w}x#{h}+#{x}+#{y}"
img
end
end
end
I am using Rails 3.2.1, Carrierwave 0.7.1, JCrop 0.9.12.

I was having a similar issue and I found that resizing the image inside the manipulate! call rather than using the "resize_to_limit" carrierwave helper method solved the problem for me.
def crop
if model.crop_x.present?
manipulate! do |img|
x = model.crop_x
y = model.crop_y
w = model.crop_w
h = model.crop_h
img.resize "500x500"
img.crop "#{w}x#{h}+#{x}+#{y}"
img
end
end
end
I also highly recommend reading this answer for more details on what is actually going on in this code.

Related

how to fix this issue ? cv2.error: OpenCV(4.1.2) ... error: (-215:Assertion failed) !ssize.empty() in function 'cv::resize'

I am trying to do rotation on multiple images in a folder but I am having this error when I put values of fx, fy greater than 0.2 in the resize function
(cv2.error: OpenCV(4.1.2) ... error: (-215:Assertion failed) !ssize.empty() in function 'cv::resize')
Although, when I try to rotate a single image and put values of fx and fy equal to 0.5, it works perfectly fine.
Is there a way to fix this issue because it is very hectic to augment images one by one? Plus the multiple images which are rotated by the code attached here, with fx and fy values equal to 0.2, have undesirable dimensions i.e the photos are very small and their quality is also reduced.
the part of code for rotation of multiple images is given below:
for imag in os.listdir(source_folder):
img = cv2.imread(os.path.join(source_folder,imag))
img = cv2.resize(img, (0,0), fx=0.5, fy=0.5)
width = img.shape[1]
height = img.shape[0]
M = cv2.getRotationMatrix2D((width/2,height/2),5,1.0)
rotated_img = cv2.warpAffine(img,M,(img.shape[1],img.shape[0]))
cv2.imwrite(os.path.join(destination_right_folder, "v4rl" + str(a) + '.jpg') , rotated_img)
#cv2.imshow("rotated_right",rotated_img)
#cv2.waitKey(0)
a += 1
Add a check after you read the image to see if it is None:
img = cv2.imread(os.path.join(source_folder,imag))
if img is None: continue
The error is happening when you call the cv2.resize() function. Maybe files are being read that are not images.

How to exchange colors between 2 images?

I have an image of spectacles with black background that I need to overlay onto a face image. To do so, I am taking the part of face image with shape same as spectacles; and put the colors of face image on black parts of the spectacles image. Then this small part of image can be put back. But I am not being able to take the correct colors from face image for the spectacles image. I tried this :
specs[np.where((hmd == [0,0,0,0]).all(axis=2))] = sub_face
specs image:
face image:
I need to put a resized specs image to face. I have resized specs image and also know the position where I will place the specs on face image. I just need to remove black background from specs and add relevant face colors so it looks like there are specs on face in a natural way.
Code I am using :
import cv2
specs = cv2.imread("rot_h0v0z0.png")
face = cv2.imread("~/Downloads/celebA/000001.png")
specs = cv2.resize(image, None, fx=0.3, fy=0.3, interpolation=cv2.INTER_AREA)
sub_face = face[0:specs.shape[0], 0:specs.shape[1]]
specs[np.where((hmd == [0,0,0,0]).all(axis=2))] = sub_face
Was able to solve it, turned out pretty simple :P
(b,g,r) = cv2.split(specs)
indices = np.where(b == [0])
for i,j in zip(indices[0], indices[1]):
specs[i,j] = sub_face[i,j]
Was able to solve it, turned out pretty simple :P
(b,g,r) = cv2.split(specs)
indices = np.where(b == [0])
for i,j in zip(indices[0], indices[1]):
specs[i,j] = sub_face[i,j]

Mirror an image in JES

I'm trying to mirror an image. That is, if, e.g., a person is facing to the left, when the program terminates I want that person to now be facing instead to the right.
I understand how mirroring works in JES, but I'm unsure how to proceed here.
Below is what I'm trying; be aware that image is a global variable declared in another function.
def flipPic(image):
width = getWidth(image)
height = getHeight(image)
for y in range(0, height):
for x in range(0, width):
left = getPixel(image, x, y)
right = getPixel(image, width-x-1, y)
color = getColor(left)
setColor(right, color)
show(image)
return image
try this
width = getWidth(pic)
height = getHeight(pic)
for y in range (0,height):
for x in range (0, width/2):
left=getPixel(pic, x, y)
right=getPixel(pic, width-x-1,y)
color1=getColor(left)
color2=getColor(right)
setColor(right, color1)
setColor(left, color2)
repaint(pic)
I personally find that repaint is confusing for newbies (like me!).
I'd suggest something like this:
def mirrorImage(image):
width = getWidth(image)
height = getHeight(image)
for y in range (0,height):
for x in range (0, width/2):
left=getPixel(pic, x, y)
right=getPixel(pic, width-x-1,y)
color1=getColor(left)
color2=getColor(right)
setColor(right, color1)
setColor(left, color2)
show(image)
return image
mirrorImage(image)
This seems to work well.. I put some comments in so you can rewrite in your own style.
feel free to ask questions but I think your question may already be answered^^
#this function will take the pixel values for a selected picture and
#past them to a new canvas but fliped over!
def flipPic(pict):
#here we take the height and width of the original picture
width=getWidth(pict)
height=getHeight(pict)
#here we make and empty canvas
newPict=makeEmptyPicture(width,height)
#the Y for loop is setting the range to working for the y axes the started the X for loop
for y in range(0, height):
#the X for loop is setting the range to work in for the x axis
for x in range(0, width):
#here we are collecting the colour information for the origional pix in range of X and
colour=getColor(getPixel(pict,x,y))
#here we are setting the colour information to its new position on the blank canvas
setColor(getPixel(newPict,width-x-1,y),colour)
#setColor(getPixel(newPict,width-x-1,height-y-1),colour)#upsidedown
show(newPict)
#drive function
pict = makePicture(pickAFile())
show(pict)
flipPic(pict)
Might be easier to read if you copy it over to JES first :D
BTW I got full marks for this one in my intro to programming class ;)

Carrierwave: Scale image if the size is larger than (conditionally create versions)

Is possible with carrierwave create a version (for example thumb) only if the image is larger than the size of the version??
Example:
version :thumb, :if => :is_thumbnable? do
process :resize_to_fit => [32,nil]
end
protected
def is_thumbnable?(file)
image ||= MiniMagick::Image.open(file.path)
if image.nil?
if image['width'] >= 32 || image['height'] >= 32
true
else
false
end
else
false
end
end
I tried them and it didn't work for me.
I get the server blocked when resizing to large images in development.
carrierwave (0.9.0)
rmagick (2.13.2)
So I get a look at the documentation: http://carrierwave.rubyforge.org/rdoc/classes/CarrierWave/RMagick.html
There is a wonderful function: resize_to_limit(width, height)
Resize the image to fit within the specified dimensions while retaining the original aspect ratio. Will only resize the image if it is larger than the specified dimensions. The resulting image may be shorter or narrower than specified in the smaller dimension but will not be larger than the specified values.
My code look like this:
version :version_name, from_version: :parent_version_name do
process resize_to_limit: [width, nil]
end
It resize to fit the width only if it's larger, respecting the ratio w/h.
I defined method in which if image exceed given width then manipulate it to your size the 32 pixels in this case. Put this code in your ImageUploader:
version :thumb do
process :resize_to_width => [32, nil]
end
def resize_to_width(width, height)
manipulate! do |img|
if img[:width] >= width
img.resize "#{width}x#{img[:height]}"
end
img = yield(img) if block_given?
img
end
end
Actually #Roza solution didn't work for me.
I had to modify method like this:
process :resize_to_width => [650, nil]
def resize_to_width(width, height)
manipulate! do |img|
if img.columns >= width
img.resize(width)
end
img = yield(img) if block_given?
img
end
end
I use rmagick (2.13.2) and rails 3.2.13, carrierwave (0.8.0)

scrapy convert_image

I use Scrapy to crawl some images, the images need to cut a part or add water mark. I overwrite the function convert_image in pipelines.py but it didn't work. The code looks like this:
class MyImagesPipeline(ImagesPipeline):
def get_media_requests(self, item, info):
for image_url in item['image_urls']:
yield Request(image_url)
def convert_image(self, image, size=None):
if image.format == 'PNG' and image.mode == 'RGBA':
background = Image.new('RGBA', image.size, (255, 255, 255))
background.paste(image, image)
image = background.convert('RGB')
elif image.mode != 'RGB':
image = image.convert('RGB')
if size:
image = image.copy()
image.thumbnail(size, Image.ANTIALIAS)
else:
# cut water image TODO use defined image replace Not cut
x,y = image.size
if(y>120):
image = image.crop((0,0,x,y-25))
buf = StringIO()
try:
image.save(buf, 'JPEG')
except Exception, ex:
raise ImageException("Cannot process image. Error: %s" % ex)
return image, buf
Any ideas?
UPDATE:
#warwaruk
how have you decided it didn't work? any exception or what? < no exception .I use this code for rewrite function item_completed.and it works good, here is the code:
def item_completed(self, results, item, info):
image_paths = [x['path'] for ok, x in results if ok]
if not image_paths:
raise DropItem("Item contains no images")
if item['refer'] == 'someurl.com' :
for a in image_paths:
o_img = os.path.join(self.store.basedir,a)
if os.path.isfile(o_img):
image = Image.open(o_img)
x,y = image.size
if(y>120):
image = image.crop((0,0,x,y-35))
image.save(o_img,'JPEG');
return item
ImagePipleline convert images to JPEG(RGB mode) automatically, and no “toggler” exists. Although you can modify its implmentaion, it may mess its other logic. So, use MediaPipeline is better -- just download the files.
You can write another application to do post-processing for your image files. It make your logic clear and make scrapy faster.