Reputation: 139
I would like to draw a circle with a diameter of 15 into a matrix of 15 by 15. For this I tried the OpenCv circle function and the shift function.
I am not sure whether I use the function in a correct way or wheather it is not possible what I would like to do.
The best I achieve is the following unsymmetric circle with a size of 16 pixels:
How can I get a symmetric circle with a diameter of 15 pixels?
The code I used:
import cv2
import numpy as np
circle_diameter = 15
circular_mask = np.zeros((circle_diameter, circle_diameter, 1), dtype='uint8')
#Draw circle with subpixel accuracy
shift = 4
factor = (1 << shift)
cv2.circle(circular_mask, (int(round((circle_diameter/2) * factor)), int(round((circle_diameter/2) * factor))), int(round((circle_diameter/2) * factor)), (255), -1, shift=shift)
circular_mask = cv2.resize(circular_mask,None,fx=5,fy=5)
cv2.imshow("mask", circular_mask)
Thanx
Upvotes: 1
Views: 1895
Reputation: 139
Mickas Code in Python:
import cv2
import numpy as np
circle_diameter = 15
circular_mask = np.zeros((circle_diameter+2, circle_diameter+2, 1), dtype='uint8') #Plus two for visualization
shift = 5
radius_low = np.floor(circle_diameter/2)
radius_shifted = (np.uint64(radius_low) << np.uint64(shift)) + (np.uint64(1)<<np.uint64((shift-1))) -1; # 7+ 2^-1 - 2^-5
circle_x = 8 << shift
circle_y = 8 << shift
cv2.circle(circular_mask, (circle_x,circle_y), int(radius_shifted), (255), -1, shift=shift)
circular_mask = cv2.resize(circular_mask,None,fx=5,fy=5)
cv2.imshow("mask", circular_mask)
Upvotes: 1
Reputation: 20130
Ok, here you go.
I'll write in C++ syntax, but should be same for Python.
It seems like the pixel coordinates in cv::circle refers to the pixel center.
cv::Mat img = cv::Mat::zeros(15, 15, CV_8UC1);
// in this code, shift must be >= 1 because of the later line (1<<(shift-1)) to add the .5 for an arbitrary shift size
const int shift = 2;
int radiusLow = 7;
int radiusShift = (radiusLow << shift) + (1<<(shift-1)); // + .5
//int x = (7 << shift) + (1<<(shift-1)); // wrong, because the pixel position seems to be the pixel center already. 7.5 would be the right ede of the pixel
//int y = (7 << shift) + (1<<(shift-1)); // wrong, because the pixel position seems to be the pixel center already. 7.5 would be the right ede of the pixel
int x = 7<<shift;
int y = 7<<shift;
cv::circle(img, cv::Point(x, y), radiusShift, cv::Scalar::all(255), -1, 8, shift);
//cv::resize(img, img, cv::Size(), 50, 50); // for visualization
cv::imshow("img", img);
cv::waitKey(0);
But the result seems to have some pixel disrectization problems, though looks like as beeing centered and with 7.5 radius. Result is resized for visualization.
Same code (but smaller resize factor) with radius 6.5 gives this image (looks like some rounding fragments during drawing).
Another test, using more bits to represent a number close to 7.5 radius, but a few bits smaller, to reduce rounding fragments in drawing:
cv::Mat img = cv::Mat::zeros(17, 17, CV_8UC1); // 2 pixels bigger for visualization of possible artifacts
const int shift = 5; // more bits for fraction
int radiusLow = 7;
int radiusShift = (radiusLow << shift) + (1<<(shift-1)) -1; // 7+ 2^-1 - 2^-5
// center of the 17x17 image
int x = 8<<shift;
int y = 8<<shift;
Upvotes: 2