Rotating an Image using own algorithm in python











up vote
6
down vote

favorite
1












For an uni assignment I have been giving the task of making my own rotating algorithm in python. This is my code so far.



import cv2
import math
import numpy as np

class rotator:

angle = 20.0
x = 330
y = 330

radians = float(angle*(math.pi/180))
img = cv2.imread('FNAF.png',0)
width,height = img.shape


def showImg(name, self):
cv2.imshow(name, self.img)
self.img = np.pad(self.img, (self.height) ,'constant', constant_values=0)
self.width,self.height = self.img.shape

def printWH(self):
print(self.width)
print(self.height)

def rotate(self):
emptyF = np.zeros((self.width,self.height),dtype="uint8")
emptyB = np.zeros((self.width,self.height),dtype="uint8")
emptyBB = np.zeros((self.width,self.height),dtype="uint8")


for i in range(self.width):
for j in range(self.height):
temp = self.img[i,j]
#forward mapping
xf = (i-self.x)*math.cos(self.radians)-(j-self.y)*math.sin(self.radians)+self.x
yf = (i-self.x)*math.sin(self.radians)+(j-self.y)*math.cos(self.radians)+self.x
#backward mapping should change the forward mapping to the original image
xbb = (i-self.x)*math.cos(self.radians)+(j-self.y)*math.sin(self.radians)+self.x
ybb = -(i-self.x)*math.sin(self.radians)+(j-self.y)*math.cos(self.radians)+self.x
xbb = int(xbb)
ybb = int(ybb)
if xf < 660 and yf < 660 and xf>0 and yf > 0:
emptyF[int(xf),int(yf)] = temp
else:
pass
if xbb < 660 and ybb < 660 and xbb>0 and ybb > 0:
emptyBB[(xbb),(ybb)] = temp
else:
pass
cv2.imshow('Forward', emptyF)
cv2.imshow('Backward', emptyBB)
def main():
rotator.showImg('normal', rotator)
rotator.printWH(rotator)
rotator.rotate(rotator)
cv2.waitKey(0)
cv2.destroyAllWindows

if __name__ == '__main__':
main()


Is there any way to improve this code or my algorithm? Any advise would be awesome.



NB. I also hav a problem with my backwards mapping. The output image has a lot of small black dots. Any suggestions to what that might be?



Please let me know.










share|improve this question







New contributor




Zorn01 is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
















  • 1




    I suspect that the black dots might be due to integer rounding of trigonometric results.
    – 200_success
    22 hours ago















up vote
6
down vote

favorite
1












For an uni assignment I have been giving the task of making my own rotating algorithm in python. This is my code so far.



import cv2
import math
import numpy as np

class rotator:

angle = 20.0
x = 330
y = 330

radians = float(angle*(math.pi/180))
img = cv2.imread('FNAF.png',0)
width,height = img.shape


def showImg(name, self):
cv2.imshow(name, self.img)
self.img = np.pad(self.img, (self.height) ,'constant', constant_values=0)
self.width,self.height = self.img.shape

def printWH(self):
print(self.width)
print(self.height)

def rotate(self):
emptyF = np.zeros((self.width,self.height),dtype="uint8")
emptyB = np.zeros((self.width,self.height),dtype="uint8")
emptyBB = np.zeros((self.width,self.height),dtype="uint8")


for i in range(self.width):
for j in range(self.height):
temp = self.img[i,j]
#forward mapping
xf = (i-self.x)*math.cos(self.radians)-(j-self.y)*math.sin(self.radians)+self.x
yf = (i-self.x)*math.sin(self.radians)+(j-self.y)*math.cos(self.radians)+self.x
#backward mapping should change the forward mapping to the original image
xbb = (i-self.x)*math.cos(self.radians)+(j-self.y)*math.sin(self.radians)+self.x
ybb = -(i-self.x)*math.sin(self.radians)+(j-self.y)*math.cos(self.radians)+self.x
xbb = int(xbb)
ybb = int(ybb)
if xf < 660 and yf < 660 and xf>0 and yf > 0:
emptyF[int(xf),int(yf)] = temp
else:
pass
if xbb < 660 and ybb < 660 and xbb>0 and ybb > 0:
emptyBB[(xbb),(ybb)] = temp
else:
pass
cv2.imshow('Forward', emptyF)
cv2.imshow('Backward', emptyBB)
def main():
rotator.showImg('normal', rotator)
rotator.printWH(rotator)
rotator.rotate(rotator)
cv2.waitKey(0)
cv2.destroyAllWindows

if __name__ == '__main__':
main()


Is there any way to improve this code or my algorithm? Any advise would be awesome.



NB. I also hav a problem with my backwards mapping. The output image has a lot of small black dots. Any suggestions to what that might be?



Please let me know.










share|improve this question







New contributor




Zorn01 is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
















  • 1




    I suspect that the black dots might be due to integer rounding of trigonometric results.
    – 200_success
    22 hours ago













up vote
6
down vote

favorite
1









up vote
6
down vote

favorite
1






1





For an uni assignment I have been giving the task of making my own rotating algorithm in python. This is my code so far.



import cv2
import math
import numpy as np

class rotator:

angle = 20.0
x = 330
y = 330

radians = float(angle*(math.pi/180))
img = cv2.imread('FNAF.png',0)
width,height = img.shape


def showImg(name, self):
cv2.imshow(name, self.img)
self.img = np.pad(self.img, (self.height) ,'constant', constant_values=0)
self.width,self.height = self.img.shape

def printWH(self):
print(self.width)
print(self.height)

def rotate(self):
emptyF = np.zeros((self.width,self.height),dtype="uint8")
emptyB = np.zeros((self.width,self.height),dtype="uint8")
emptyBB = np.zeros((self.width,self.height),dtype="uint8")


for i in range(self.width):
for j in range(self.height):
temp = self.img[i,j]
#forward mapping
xf = (i-self.x)*math.cos(self.radians)-(j-self.y)*math.sin(self.radians)+self.x
yf = (i-self.x)*math.sin(self.radians)+(j-self.y)*math.cos(self.radians)+self.x
#backward mapping should change the forward mapping to the original image
xbb = (i-self.x)*math.cos(self.radians)+(j-self.y)*math.sin(self.radians)+self.x
ybb = -(i-self.x)*math.sin(self.radians)+(j-self.y)*math.cos(self.radians)+self.x
xbb = int(xbb)
ybb = int(ybb)
if xf < 660 and yf < 660 and xf>0 and yf > 0:
emptyF[int(xf),int(yf)] = temp
else:
pass
if xbb < 660 and ybb < 660 and xbb>0 and ybb > 0:
emptyBB[(xbb),(ybb)] = temp
else:
pass
cv2.imshow('Forward', emptyF)
cv2.imshow('Backward', emptyBB)
def main():
rotator.showImg('normal', rotator)
rotator.printWH(rotator)
rotator.rotate(rotator)
cv2.waitKey(0)
cv2.destroyAllWindows

if __name__ == '__main__':
main()


Is there any way to improve this code or my algorithm? Any advise would be awesome.



NB. I also hav a problem with my backwards mapping. The output image has a lot of small black dots. Any suggestions to what that might be?



Please let me know.










share|improve this question







New contributor




Zorn01 is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.











For an uni assignment I have been giving the task of making my own rotating algorithm in python. This is my code so far.



import cv2
import math
import numpy as np

class rotator:

angle = 20.0
x = 330
y = 330

radians = float(angle*(math.pi/180))
img = cv2.imread('FNAF.png',0)
width,height = img.shape


def showImg(name, self):
cv2.imshow(name, self.img)
self.img = np.pad(self.img, (self.height) ,'constant', constant_values=0)
self.width,self.height = self.img.shape

def printWH(self):
print(self.width)
print(self.height)

def rotate(self):
emptyF = np.zeros((self.width,self.height),dtype="uint8")
emptyB = np.zeros((self.width,self.height),dtype="uint8")
emptyBB = np.zeros((self.width,self.height),dtype="uint8")


for i in range(self.width):
for j in range(self.height):
temp = self.img[i,j]
#forward mapping
xf = (i-self.x)*math.cos(self.radians)-(j-self.y)*math.sin(self.radians)+self.x
yf = (i-self.x)*math.sin(self.radians)+(j-self.y)*math.cos(self.radians)+self.x
#backward mapping should change the forward mapping to the original image
xbb = (i-self.x)*math.cos(self.radians)+(j-self.y)*math.sin(self.radians)+self.x
ybb = -(i-self.x)*math.sin(self.radians)+(j-self.y)*math.cos(self.radians)+self.x
xbb = int(xbb)
ybb = int(ybb)
if xf < 660 and yf < 660 and xf>0 and yf > 0:
emptyF[int(xf),int(yf)] = temp
else:
pass
if xbb < 660 and ybb < 660 and xbb>0 and ybb > 0:
emptyBB[(xbb),(ybb)] = temp
else:
pass
cv2.imshow('Forward', emptyF)
cv2.imshow('Backward', emptyBB)
def main():
rotator.showImg('normal', rotator)
rotator.printWH(rotator)
rotator.rotate(rotator)
cv2.waitKey(0)
cv2.destroyAllWindows

if __name__ == '__main__':
main()


Is there any way to improve this code or my algorithm? Any advise would be awesome.



NB. I also hav a problem with my backwards mapping. The output image has a lot of small black dots. Any suggestions to what that might be?



Please let me know.







python algorithm image numpy opencv






share|improve this question







New contributor




Zorn01 is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.











share|improve this question







New contributor




Zorn01 is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.









share|improve this question




share|improve this question






New contributor




Zorn01 is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.









asked 22 hours ago









Zorn01

312




312




New contributor




Zorn01 is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.





New contributor





Zorn01 is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.






Zorn01 is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.








  • 1




    I suspect that the black dots might be due to integer rounding of trigonometric results.
    – 200_success
    22 hours ago














  • 1




    I suspect that the black dots might be due to integer rounding of trigonometric results.
    – 200_success
    22 hours ago








1




1




I suspect that the black dots might be due to integer rounding of trigonometric results.
– 200_success
22 hours ago




I suspect that the black dots might be due to integer rounding of trigonometric results.
– 200_success
22 hours ago










1 Answer
1






active

oldest

votes

















up vote
3
down vote













The most common method for getting rid of the black dots is to paint over each pixel of the entire destination image with pixels copied from computed positions in the source image, instead of painting the source image pixels into computed positions in the destination image.



for i in range(660):
for j in range(660):
xb = int(...)
yb = int(...)
if xb in range(self.width) and yb in range(self.height):
emptyF[i, j] = self.img[xb, yb]


Computing destination pixels positions from the source pixel positions may result in tiny areas unpainted in the destination due to numeric errors/limits.



Computing source pixels positions from the destination pixel position may result in a pixel value being copied to two adjacent locations, and other pixels never being copied from, but this is usually/often unnoticeable.






share|improve this answer





















  • Well that worked! Thanks man. How can you apply this method for both the forward and backwards mapping?
    – Zorn01
    12 hours ago










  • However, I can't seem to get the range(660) right instead of my range(self.width). Any suggestions to that?
    – Zorn01
    12 hours ago










  • Apply the same technique for both forward & reverse rotations. Ie, duplicate the last 4 lines and change xb/xf/emptyF to xf/yf/emptyBB. I don’t know what you mean by “get range(660) right” Even 660 is a magic number whose origin is a mystery. If code does not work properly, StackOverflow is a more appropriate forum to get help fixing code.
    – AJNeufeld
    9 hours ago










  • Going from destination pixels to source pixels is the right idea, so that each destination pixel is painted just once. But looping in native Python over the individual pixels is going to be slow — better to use numpy.meshgrid to generate the coordinates and then transform them all at once. See §2 of this answer for details.
    – Gareth Rees
    7 hours ago













Your Answer





StackExchange.ifUsing("editor", function () {
return StackExchange.using("mathjaxEditing", function () {
StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
});
});
}, "mathjax-editing");

StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "196"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});






Zorn01 is a new contributor. Be nice, and check out our Code of Conduct.










 

draft saved


draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f208101%2frotating-an-image-using-own-algorithm-in-python%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























1 Answer
1






active

oldest

votes








1 Answer
1






active

oldest

votes









active

oldest

votes






active

oldest

votes








up vote
3
down vote













The most common method for getting rid of the black dots is to paint over each pixel of the entire destination image with pixels copied from computed positions in the source image, instead of painting the source image pixels into computed positions in the destination image.



for i in range(660):
for j in range(660):
xb = int(...)
yb = int(...)
if xb in range(self.width) and yb in range(self.height):
emptyF[i, j] = self.img[xb, yb]


Computing destination pixels positions from the source pixel positions may result in tiny areas unpainted in the destination due to numeric errors/limits.



Computing source pixels positions from the destination pixel position may result in a pixel value being copied to two adjacent locations, and other pixels never being copied from, but this is usually/often unnoticeable.






share|improve this answer





















  • Well that worked! Thanks man. How can you apply this method for both the forward and backwards mapping?
    – Zorn01
    12 hours ago










  • However, I can't seem to get the range(660) right instead of my range(self.width). Any suggestions to that?
    – Zorn01
    12 hours ago










  • Apply the same technique for both forward & reverse rotations. Ie, duplicate the last 4 lines and change xb/xf/emptyF to xf/yf/emptyBB. I don’t know what you mean by “get range(660) right” Even 660 is a magic number whose origin is a mystery. If code does not work properly, StackOverflow is a more appropriate forum to get help fixing code.
    – AJNeufeld
    9 hours ago










  • Going from destination pixels to source pixels is the right idea, so that each destination pixel is painted just once. But looping in native Python over the individual pixels is going to be slow — better to use numpy.meshgrid to generate the coordinates and then transform them all at once. See §2 of this answer for details.
    – Gareth Rees
    7 hours ago

















up vote
3
down vote













The most common method for getting rid of the black dots is to paint over each pixel of the entire destination image with pixels copied from computed positions in the source image, instead of painting the source image pixels into computed positions in the destination image.



for i in range(660):
for j in range(660):
xb = int(...)
yb = int(...)
if xb in range(self.width) and yb in range(self.height):
emptyF[i, j] = self.img[xb, yb]


Computing destination pixels positions from the source pixel positions may result in tiny areas unpainted in the destination due to numeric errors/limits.



Computing source pixels positions from the destination pixel position may result in a pixel value being copied to two adjacent locations, and other pixels never being copied from, but this is usually/often unnoticeable.






share|improve this answer





















  • Well that worked! Thanks man. How can you apply this method for both the forward and backwards mapping?
    – Zorn01
    12 hours ago










  • However, I can't seem to get the range(660) right instead of my range(self.width). Any suggestions to that?
    – Zorn01
    12 hours ago










  • Apply the same technique for both forward & reverse rotations. Ie, duplicate the last 4 lines and change xb/xf/emptyF to xf/yf/emptyBB. I don’t know what you mean by “get range(660) right” Even 660 is a magic number whose origin is a mystery. If code does not work properly, StackOverflow is a more appropriate forum to get help fixing code.
    – AJNeufeld
    9 hours ago










  • Going from destination pixels to source pixels is the right idea, so that each destination pixel is painted just once. But looping in native Python over the individual pixels is going to be slow — better to use numpy.meshgrid to generate the coordinates and then transform them all at once. See §2 of this answer for details.
    – Gareth Rees
    7 hours ago















up vote
3
down vote










up vote
3
down vote









The most common method for getting rid of the black dots is to paint over each pixel of the entire destination image with pixels copied from computed positions in the source image, instead of painting the source image pixels into computed positions in the destination image.



for i in range(660):
for j in range(660):
xb = int(...)
yb = int(...)
if xb in range(self.width) and yb in range(self.height):
emptyF[i, j] = self.img[xb, yb]


Computing destination pixels positions from the source pixel positions may result in tiny areas unpainted in the destination due to numeric errors/limits.



Computing source pixels positions from the destination pixel position may result in a pixel value being copied to two adjacent locations, and other pixels never being copied from, but this is usually/often unnoticeable.






share|improve this answer












The most common method for getting rid of the black dots is to paint over each pixel of the entire destination image with pixels copied from computed positions in the source image, instead of painting the source image pixels into computed positions in the destination image.



for i in range(660):
for j in range(660):
xb = int(...)
yb = int(...)
if xb in range(self.width) and yb in range(self.height):
emptyF[i, j] = self.img[xb, yb]


Computing destination pixels positions from the source pixel positions may result in tiny areas unpainted in the destination due to numeric errors/limits.



Computing source pixels positions from the destination pixel position may result in a pixel value being copied to two adjacent locations, and other pixels never being copied from, but this is usually/often unnoticeable.







share|improve this answer












share|improve this answer



share|improve this answer










answered 19 hours ago









AJNeufeld

3,625317




3,625317












  • Well that worked! Thanks man. How can you apply this method for both the forward and backwards mapping?
    – Zorn01
    12 hours ago










  • However, I can't seem to get the range(660) right instead of my range(self.width). Any suggestions to that?
    – Zorn01
    12 hours ago










  • Apply the same technique for both forward & reverse rotations. Ie, duplicate the last 4 lines and change xb/xf/emptyF to xf/yf/emptyBB. I don’t know what you mean by “get range(660) right” Even 660 is a magic number whose origin is a mystery. If code does not work properly, StackOverflow is a more appropriate forum to get help fixing code.
    – AJNeufeld
    9 hours ago










  • Going from destination pixels to source pixels is the right idea, so that each destination pixel is painted just once. But looping in native Python over the individual pixels is going to be slow — better to use numpy.meshgrid to generate the coordinates and then transform them all at once. See §2 of this answer for details.
    – Gareth Rees
    7 hours ago




















  • Well that worked! Thanks man. How can you apply this method for both the forward and backwards mapping?
    – Zorn01
    12 hours ago










  • However, I can't seem to get the range(660) right instead of my range(self.width). Any suggestions to that?
    – Zorn01
    12 hours ago










  • Apply the same technique for both forward & reverse rotations. Ie, duplicate the last 4 lines and change xb/xf/emptyF to xf/yf/emptyBB. I don’t know what you mean by “get range(660) right” Even 660 is a magic number whose origin is a mystery. If code does not work properly, StackOverflow is a more appropriate forum to get help fixing code.
    – AJNeufeld
    9 hours ago










  • Going from destination pixels to source pixels is the right idea, so that each destination pixel is painted just once. But looping in native Python over the individual pixels is going to be slow — better to use numpy.meshgrid to generate the coordinates and then transform them all at once. See §2 of this answer for details.
    – Gareth Rees
    7 hours ago


















Well that worked! Thanks man. How can you apply this method for both the forward and backwards mapping?
– Zorn01
12 hours ago




Well that worked! Thanks man. How can you apply this method for both the forward and backwards mapping?
– Zorn01
12 hours ago












However, I can't seem to get the range(660) right instead of my range(self.width). Any suggestions to that?
– Zorn01
12 hours ago




However, I can't seem to get the range(660) right instead of my range(self.width). Any suggestions to that?
– Zorn01
12 hours ago












Apply the same technique for both forward & reverse rotations. Ie, duplicate the last 4 lines and change xb/xf/emptyF to xf/yf/emptyBB. I don’t know what you mean by “get range(660) right” Even 660 is a magic number whose origin is a mystery. If code does not work properly, StackOverflow is a more appropriate forum to get help fixing code.
– AJNeufeld
9 hours ago




Apply the same technique for both forward & reverse rotations. Ie, duplicate the last 4 lines and change xb/xf/emptyF to xf/yf/emptyBB. I don’t know what you mean by “get range(660) right” Even 660 is a magic number whose origin is a mystery. If code does not work properly, StackOverflow is a more appropriate forum to get help fixing code.
– AJNeufeld
9 hours ago












Going from destination pixels to source pixels is the right idea, so that each destination pixel is painted just once. But looping in native Python over the individual pixels is going to be slow — better to use numpy.meshgrid to generate the coordinates and then transform them all at once. See §2 of this answer for details.
– Gareth Rees
7 hours ago






Going from destination pixels to source pixels is the right idea, so that each destination pixel is painted just once. But looping in native Python over the individual pixels is going to be slow — better to use numpy.meshgrid to generate the coordinates and then transform them all at once. See §2 of this answer for details.
– Gareth Rees
7 hours ago












Zorn01 is a new contributor. Be nice, and check out our Code of Conduct.










 

draft saved


draft discarded


















Zorn01 is a new contributor. Be nice, and check out our Code of Conduct.













Zorn01 is a new contributor. Be nice, and check out our Code of Conduct.












Zorn01 is a new contributor. Be nice, and check out our Code of Conduct.















 


draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f208101%2frotating-an-image-using-own-algorithm-in-python%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

Ottavio Pratesi

Tricia Helfer

15 giugno