I am attempting to solve a problem where I have a region of size = width * height and then have to find a sub-region within the region at a location x, y and of size width_1 * height_1.
The values are:
Region_width = 71680
Region_height = 39680
Sub_location_x=272
Sub_location_y=130
Sub_width=372
Sub_height=519
The code I am attempting to implement I think should be like this.
#Width height of box
region_width = 71680
region_height = 39680
x = 272
y = 130
sub_width = 372
sub_height = 519
#Create numpy array of width and height (This I am unsure of)
Region_array = np.array(width, height)
#Pull out sub box (This I am also unsure of)
Sub_box = Region_array[x: x + sub_width, y: y + sub_height]
Would really appreciate any help or insight has to how I solve the problem.
Related
I'm facing a little issue in my code. I have a dataframe of coords and angels.
I want to draw a line from a certain xy coords to the edge of the image on a certain angle (say 45 degree).
How can I do that using PIL? Looping over x2 = x + length*cos(angle) doesn't look like a good solution (but I might be wrong here).
Thanks in advance.
Thanks for posting your solution. I've found a good one.
import math
def get_coords(x, y, angle, imwidth, imheight):
x1_length = (x-imwidth) / math.cos(angle)
y1_length = (y-imheight) / math.sin(angle)
length = max(abs(x1_length), abs(y1_length))
endx1 = x + length * math.cos(math.radians(angle))
endy1 = y + length * math.sin(math.radians(angle))
x2_length = (x-imwidth) / math.cos(angle+180)
y2_length = (y-imheight) / math.sin(angle+180)
length = max(abs(x2_length), abs(y2_length))
endx2 = x + length * math.cos(math.radians(angle+180))
endy2 = y + length * math.sin(math.radians(angle+180))
return endx1, endy1, endx2, endy2
Then I just draw a line between (endx1, endy1) and (endx2, endy2).
If you have a better solution, I would be very interested to see it.
I have been developing an app for someone and we quickly realized that the app looks different between our laptops (and on my tablet its un-usable because of the ppi). I looked up what the problem was so I used starting_frame.tk.call('tk', 'scaling', factor) to normalize the PPI across all devices. What I quickly realized, however, was the program will still be too big or too small depending on the screen ( i have a resolution set at root.geometry("1280x960") . In order to combat all of these problems, I created the code below:
root = tk.Tk()
dpi = root.winfo_fpixels('1i')
factor = dpi / 72
width = root.winfo_screenwidth()
height = root.winfo_screenheight()
ratio_1 = width * height
ratio_2 = 1
r2_width = 4
r2_height = 3
while (ratio_1 / ratio_2) != 1.6875:
r2_height = r2_width / 1.33333333333
ratio_2 = r2_width * r2_height
r2_width = r2_width + 1
if (ratio_1/ratio_2) <= 1.6875:
break
if width + 1 == r2_width:
break
root.geometry(str(r2_width) + "x"+ str(int(r2_height)))
starting_frame = tk.Canvas(root)
factor_multiplier = (.40*factor) +.46
factor = factor/factor_multiplier
starting_frame.tk.call('tk', 'scaling', factor)
starting_frame.place(height=int(r2_height), width = r2_width)
Let me break this down:
dpi = root.winfo_fpixels('1i')
factor = dpi / 72
width = root.winfo_screenwidth()
height = root.winfo_screenheight()
this just grabs the ppi of the device and the screen res....
ratio_1 = width * height
ratio_2 = 1
r2_width = 4
r2_height = 3
while (ratio_1 / ratio_2) != 1.6875:
r2_height = r2_width / 1.33333333333
ratio_2 = r2_width * r2_height
r2_width = r2_width + 1
if (ratio_1/ratio_2) <= 1.6875:
break
if width + 1 == r2_width:
break
root.geometry(str(r2_width) + "x"+ str(int(r2_height)))
This basically takes my 16x9 display and finds a 4:3 resolution that is 88% or so the area of my screen res (i just think its a good size and is that my program is based around).
factor_multiplier = (.40*factor) +.46
factor = factor/factor_multiplier
this converts the ppi of any screen so that the size of the text and stuff is normalized across displays (I assumed a linear relation).
starting_frame.tk.call('tk', 'scaling', factor)
starting_frame.place(height=int(r2_height), width = r2_width)
this is just making a frame and stuff based on my calculated new ppi and res.
While this sorta works, and then all of my hard coded text positions are multiplied by my factor_multiplier , it is a very sloppy and long way of doing this. please tell me there is a better way because I have been looking and I can't find anything that suits my needs.
You can the ctypes Python library. This following setting in the ctypes library sets DPI awareness.
import ctypes
ctypes.windll.shcore.SetProcessDpiAwareness(1)
Having trouble with this particular task (using JES 4.3). The task is to scale down a QR code image using Python to a 25 x 25 image, and to remove the white border (quiet zone) from the image. I have no trouble scaling it down, but the removal of the quiet zone is troubling. I believe it must be done before the scaling itself, and the quiet zone width can vary. Thus it appears that I need to remove each outer layer of pixels one by one until the program detects that its no longer the quiet zone. Quite sure a while loop is required, but have no clue how to implement that effectively. My code so far:
def reduce(qrPicture):
file = makePicture(qrPicture)
myPicture = duplicatePicture(file)
width = getWidth(myPicture)
height = getHeight(myPicture)
newPicture = makeEmptyPicture(25, 25)
newWidth = getWidth(newPicture)
newHeight = getHeight(newPicture)
basePixel = getPixelAt(myPicture, 0, 0)
startX = 0
startY = 0
xWidth = width/float(newWidth)
yHeight = height/float(newHeight)
for x in range(startX, newWidth):
for y in range(startY, newHeight):
smallPix = getPixel(newPicture, x, y)
pixelX = x*xWidth;
pixelY = y*yHeight;
oPixel = getPixel(myPicture, int(pixelX), int(pixelY))
setColor(smallPix, getColor(oPixel))
As mentioned, this simply scales the image to 25 x 25 but does not remove the quiet zone. Can someone tell me how to implement this removal of the quiet zone? Thanks.
def findQuietZone(pic):
width = getWidth(pic)
height = getHeight(pic)
for x in range(0, width):
for y in range(0, height):
px = getPixel(pic, x, y)
color = getColor(px)
if (colour != white):
value = getX(px)
quietZone = width - value
I am trying to implement a program, that will increase the width of an image by one pixel. I then want to take the new maximum x ordinate and put this with a random y ordinate (that is within the range of the image) to create a new pixel.
for x in range (0,getWidth(pic)):
for y in range (0,getHeight(pic)):
X=getWidth(pic)
newX = (X+1)
colr=(255,0,0)
newPixel = getPixel (pic, newX, y)//line 25
setColor(newPixel, colr)
Y=getHeight(pic)
newY= (Y+1)
newPixel = getPixel( pic,x, newY)
setColor(newPixel, colr)
I get this error:
getPixel(picture,x,y): x (= 226) is less than 0 or bigger than the width (= 224)
The error was:
Inappropriate argument value (of correct type).
An error occurred attempting to pass an argument to a function.
Please check line 25 of D:\bla bla
I understand it is out of the range. What am I doing wrong?
Here is generalized approach to increase the size of an image keeping its current content:
Feel free to adapt.
# Increase a picture given an offset, a color and the anciant
# content must be centered or not.
# Offsets must be positive.
def increaseAndCopy(pic, offsetX, offsetY, bg_color=black, center=True):
# Offsets must be positive
if (offsetX < 0.0) or (offsetY < 0.0):
printNow("Error: Offsets must be positive !")
return None
new_w = pic.getWidth() + int(2*offsetX)
new_h = pic.getHeight() + int(2*offsetY)
startX = 0
startY = 0
if (center) and (offsetX > 1.0):
startX = int(offsetX)
if (center) and (offsetY > 1.0):
startY = int(offsetY)
new_pic = makeEmptyPicture(new_w, new_h)
# Fill with background color
setAllPixelsToAColor(new_pic, bg_color)
# Process copy
for x in xrange(pic.getWidth()):
for y in xrange(pic.getHeight()):
px = getPixel(pic, x, y)
new_px = getPixel(new_pic, x + startX, y + startY)
setColor(new_px, getColor(px))
return new_pic
file = pickAFile()
picture = makePicture(file)
# Pass an offset of 0.5 to increase by 1 pixel
#new_picture = increaseAndCopy(picture, 0.5, 0, blue)
new_picture = increaseAndCopy(picture, 10, 20, gray, True)
if (new_picture):
writePictureTo(new_picture, "/home/biggerPic.png")
show(new_picture)
Output (Painting by Jean-Michel Basquiat):
...........................................................
How can you get something that an object does not have?
newPixel = getPixel (pic, newX, y)//line 25
The original image remains sized at getWidth(pic) but you are asking for a pixel at getWidth(pic) + 1 which does not exist.
You can enlarge the image by copying it to a new picture similar to this answer.
...
newPic=makeEmptyPicture(newX,newY)
xstart=0
ystart=0
for y in range(ystart,newY):
for x in range(xstart, newX):
if x == newX or y == newY:
colour=(255,0,0)
else:
oldPixel=getPixel(oldPic,x,y)
colour=getColor(oldPixel)
newPixel=getPixel(newPic,x,y)
setColor(newPixel,colour)
explore(newPic)
community.
I know that there are many answers here, manuals, tutorials and references over the internets and amny more about this question. Also I know that knowledge of linear algebra is required.
But when I think about time to figuring out all the theory and solving exercises in practice - my head is blowing off and I can't do the simplest things :(
Please, if you know a little fast solution how to make rotation of text over its center before rendering it - tell me, pleeease.
For now I have:
#...
cr.move_to(*text_center)
myX, myY = text_center[0] - (width / 2), text_center[1] + (height / 2)
cr.save()
cr.translate(myX, myY)
cr.rotate(radians(text_angle))
cr.show_text(letter)
cr.restore()
#...
But my letter isn't rotating around itself. It's just like falling down to the right side :(
I know that my code isn't right. Maybe I miss transformation but I don't know how to make it right.
UPDATE: Unfortunately, text are not affected by translations, so
cr.translate(10000, 10000)
cr.rotate(radians(15))
cr.show_text("hello")
will be exactly the same as
cr.rotate(radians(15))
cr.show_text("hello")
And I don't know how to make text rotation over its center without making new surface or something (like new layer in graphic processor) :(
At least on the version of cairo available on my machine (1.8.8), the following approach works for me:
def text(ctx, string, pos, theta = 0.0, face = 'Georgia', font_size = 18):
ctx.save()
# build up an appropriate font
ctx.select_font_face(face , cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_NORMAL)
ctx.set_font_size(font_size)
fascent, fdescent, fheight, fxadvance, fyadvance = ctx.font_extents()
x_off, y_off, tw, th = ctx.text_extents(string)[:4]
nx = -tw/2.0
ny = fheight/2
ctx.translate(pos[0], pos[1])
ctx.rotate(theta)
ctx.translate(nx, ny)
ctx.move_to(0,0)
ctx.show_text(string)
ctx.restore()
Which can be used in the following way:
width = 500
height = 500
surface = cairo.ImageSurface(cairo.FORMAT_RGB24, width, height)
ctx = cairo.Context(surface)
ctx.set_source_rgb(1,1,1)
rect(ctx, (0,0), (width, height), stroke=False)
ctx.set_source_rgb(0,0,0)
for i in xrange(5):
for j in xrange(5):
x = 100 * i + 20
y = 100 * j + 20
theta = math.pi*0.25*(5*i+j)
text(ctx, 'hello world', (x, y), theta, font_size=15)
surface.write_to_png('text-demo.png')
OK so cairo allows for text move_to and rotate. This means that what you want is to figure out (x,y) for move_to (T), such that when you rotate (R), the center point of your text is at your desired location, c=(cx,cy):
So you have to solve the equation Mv = c, where v is the text center relative to the text origin:
M = T*R
T = (1 0 x)
(0 1 y)
(0 0 1)
R = (cos r -sin r 0)
(sin r cos r 0)
(0 0 1)
v = (w/2, h', 1)
c = (cx, cy, 1)
h' = h/2 - (h - y_bearing)
Sanity checks:
when r is 0 (no rotation), you get x=cx-w/2, y=cy-h', which you know
is the correct answer
when r=-90 (text sideways, with "up" towards the right), you get what you expect,
ie x = cx - h' and y = cy + w/2
For python code, you will have to rewrite the above equation so you end up with A*t=b, where t=(x,y), and you will compute t = inv(A)*b. Then, you will simply do
cr.move_to(x, y)
cr.rotate(r)
cr.show_text(yourtext)
Note that the coordinate system in cairo has +y going down so there will be a couple signs to fix, and maybe y_bearing is not correct, but you get the idea.
Class function based on above input with multi-line text support.
def text(self, text, x, y, rotation=0, fontName="Arial", fontSize=10, verticalPadding=0):
rotation = rotation * math.pi / 180
self.ctx.select_font_face(fontName, cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_NORMAL)
self.ctx.set_font_size(fontSize)
fascent, fdescent, fheight, fxadvance, fyadvance = self.ctx.font_extents()
self.ctx.save()
self.ctx.translate(x, y)
self.ctx.rotate(rotation)
lines = text.split("\n")
for i in xrange(len(lines)):
line = lines[i]
xoff, yoff, textWidth, textHeight = self.ctx.text_extents(line)[:4]
offx = -textWidth / 2.0
offy = (fheight / 2.0) + (fheight + verticalPadding) * i
self.ctx.move_to(offx, offy)
self.ctx.show_text(line)
self.ctx.restore()
Should
myX, myY = text_center[0] + (height / 2), text_center[1] - (width / 2)
be
myX, myY = text_center[0] - (width / 2), text_center[1] + (height / 2)
?
That might explain why it's falling down to the right side.