I recently study with Dicom images deep learning. I want to move my dicom image processing code from python to c++.
Following is my python code.
def window_img(dcm, width=None, level=None):
pixels = dcm.pixel_array * dcm.RescaleSlope + dcm.RescaleIntercept
lower = level - (width / 2)
upper = level + (width / 2)
pixels[pixels<lower] = lower
pixels[pixels>upper] = upper
pixels = (pixels - (level - width//2)) / width
return pixels
def meta_dicom_convert(dcm, ww, wc):
b = window_img(dcm, ww[0], wc[0])
g = window_img(dcm, ww[1], wc[1])
r = window_img(dcm, ww[2], wc[2])
image = np.concatenate([b, g, r], axis=2)
return image
And I try to do something like this in c++. However, I only found some method like cv::merge. I use cv::merge. But it seems a little differet from images combined by np.concatenate.
My C++ code:
DcmFileFormat dfile;
OFCondition result = dfile.loadFile("D:\\python\\RSNA\\stage_2_train\\ID_c8355f255.dcm");
DcmDataset *dcmdataset = dfile.getDataset();
double slope, intercept;
dcmdataset->findAndGetFloat64(DCM_RescaleSlope, slope);
dcmdataset->findAndGetFloat64(DCM_RescaleIntercept, intercept);
DicomImage dcmimage_brain("D:\\python\\RSNA\\stage_2_train\\ID_c8355f255.dcm");
DicomImage dcmimage_subdural("D:\\python\\RSNA\\stage_2_train\\ID_c8355f255.dcm");
DicomImage dcmimage_bone("D:\\python\\RSNA\\stage_2_train\\ID_c8355f255.dcm");
int nWidth = dcmimage_brain.getWidth();
int nHeight = dcmimage_brain.getHeight();
cout << "size = " << nWidth << " x " << nHeight << endl;
int wcenter = 40, wwidth = 80;
int lower = wcenter - (wwidth / 2);
int upper = wcenter + (wwidth / 2);
dcmimage_brain.setWindow(wcenter, wwidth);
Uint8 *pixeldata_brain = (Uint8*)(dcmimage_brain.getOutputData(8));
if (pixeldata_brain)
{
for (int i = 0; i < nWidth * nHeight; ++i) {
if (pixeldata_brain[i] < lower)
pixeldata_brain[i] = lower;
if (pixeldata_brain[i] > upper)
pixeldata_brain[i] = upper;
pixeldata_brain[i] = (255 * (pixeldata_brain[i] - lower)) / (upper - lower);
}
}
Mat brain = Mat(nWidth, nHeight, CV_8UC1, pixeldata_brain);
//brain.convertTo(brain, CV_8UC1);
wcenter = 80;
wwidth = 200;
lower = wcenter - (wwidth / 2);
upper = wcenter + (wwidth / 2);
dcmimage_subdural.setWindow(wcenter, wwidth);
Uint8 *pixeldata_subdural = (Uint8*)(dcmimage_subdural.getOutputData(8));
if (pixeldata_subdural)
{
for (int i = 0; i < nWidth * nHeight; ++i) {
if (pixeldata_subdural[i] < lower)
pixeldata_subdural[i] = lower;
if (pixeldata_subdural[i] > upper)
pixeldata_subdural[i] = upper;
pixeldata_subdural[i] = (255 * (pixeldata_subdural[i] - lower)) / (upper - lower);
}
}
Mat subdural = Mat(nWidth, nHeight, CV_8UC1, pixeldata_subdural);
//subdural.convertTo(subdural, CV_8UC1);
wcenter = 40;
wwidth = 380;
lower = wcenter - (wwidth / 2);
upper = wcenter + (wwidth / 2);
dcmimage_bone.setWindow(wcenter, wwidth);
Uint8 *pixeldata_bone = (Uint8*)(dcmimage_bone.getOutputData(8));
if (pixeldata_bone) {
for (int i = 0; i < nWidth * nHeight; ++i) {
if (pixeldata_bone[i] < lower)
pixeldata_bone[i] = lower;
if (pixeldata_bone[i] > upper)
pixeldata_bone[i] = upper;
pixeldata_bone[i] = (255 * (pixeldata_bone[i] - lower) / (upper - lower));
}
}
Mat bone = Mat(nWidth, nHeight, CV_8UC1, pixeldata_bone);
imshow("bone", bone);
//bone.convertTo(bone, CV_8UC1);
//Mat bone = Mat(nWidth, nHeight, CV_16UC1, pbone);
//bone.convertTo(bone, CV_8UC1);
// new Image size
Mat image = Mat::zeros(nWidth, nHeight, CV_8UC3);
vector<Mat> channels;
split(image, channels);
channels.at(0) = brain;
channels.at(1) = subdural;
channels.at(2) = bone;
merge(channels, image);
imshow("mergeImage", image);
waitKey();
result image: (left side: cv::merge) (right side: np.concatenate)
enter image description here
Is cv::merge actually not just concatenate images in channels?
Is there any other method I can use in c++ to do thing like np.concatenate?
Any reply would be appreciate. thanks
Related
I am trying to implement pan and zoom functions in my RTSP camera stream using Python. I want to be able to use my mouse wheel to zoom in and out from the video and click and drag to move the video around. However, I have not been able to find any tutorials on handling these mouse events in OpenCV.
Is there such a way or will I have resort to using keystrokes to pan and zoom my video?
You can use mouse event and imshow to achieve this function.
def mouse_event_callback(self, event,x,y,flags,param):
if event == cv2.EVENT_LBUTTONDOWN:
elif event == cv2.EVENT_MOUSEMOVE:
elif event == cv2.EVENT_LBUTTONUP:
elif event == cv2.EVENT_MOUSEWHEEL:
...
cv2.namedWindow('Test')
cv2.setMouseCallback('Test',self.mouse_event_callback)
while True:
cv2.imshow('Test',img)
The basic idea is deciding the scale changed every time on mouse wheel. After you get the current scale (v.s. origin image) and correct region of image you want to show on screen, you can get the position and length of rectangle on scaled image. So you can draw this rectangle on scaled image.
In my github,checking OnMouseWheel () and RefreshSrcView () in Fastest_Image_Pattern_Matching/ELCVMatchTool/ELCVMatchToolDlg.cpp may give what you want.
Although it's c++ code, but only imshow () and resize () are used. Focusing on how I change the scale and how the new rectangle to be draw in scaled image will be enough.
Effect:
Part of the code:
BOOL CELCVMatchToolDlg::OnMouseWheel (UINT nFlags, short zDelta, CPoint pt)
{
POINT pointCursor;
GetCursorPos (&pointCursor);
ScreenToClient (&pointCursor);
// TODO: 在此加入您的訊息處理常式程式碼和 (或) 呼叫預設值
if (zDelta > 0)
{
if (m_iScaleTimes == MAX_SCALE_TIMES)
return TRUE;
else
m_iScaleTimes++;
}
if (zDelta < 0)
{
if (m_iScaleTimes == MIN_SCALE_TIMES)
return TRUE;
else
m_iScaleTimes--;
}
CRect rect;
//GetWindowRect (rect);
GetDlgItem (IDC_STATIC_SRC_VIEW)->GetWindowRect (rect);//重要
if (m_iScaleTimes == 0)
g_dCompensationX = g_dCompensationY = 0;
int iMouseOffsetX = pt.x - (rect.left + 1);
int iMouseOffsetY = pt.y - (rect.top + 1);
double dPixelX = (m_hScrollBar.GetScrollPos () + iMouseOffsetX + g_dCompensationX) / m_dNewScale;
double dPixelY = (m_vScrollBar.GetScrollPos () + iMouseOffsetY + g_dCompensationY) / m_dNewScale;
m_dNewScale = m_dSrcScale * pow (SCALE_RATIO, m_iScaleTimes);
if (m_iScaleTimes != 0)
{
int iWidth = m_matSrc.cols;
int iHeight = m_matSrc.rows;
m_hScrollBar.SetScrollRange (0, int (m_dNewScale * iWidth - m_dSrcScale * iWidth) - 1 + BAR_SIZE);
m_vScrollBar.SetScrollRange (0, int (m_dNewScale * iHeight - m_dSrcScale * iHeight) - 1 + BAR_SIZE);
int iBarPosX = int (dPixelX * m_dNewScale - iMouseOffsetX + 0.5);
m_hScrollBar.SetScrollPos (iBarPosX);
m_hScrollBar.ShowWindow (SW_SHOW);
g_dCompensationX = -iBarPosX + (dPixelX * m_dNewScale - iMouseOffsetX);
int iBarPosY = int (dPixelY * m_dNewScale - iMouseOffsetY + 0.5);
m_vScrollBar.SetScrollPos (iBarPosY);
m_vScrollBar.ShowWindow (SW_SHOW);
g_dCompensationY = -iBarPosY + (dPixelY * m_dNewScale - iMouseOffsetY);
//滑塊大小
SCROLLINFO infoH;
infoH.cbSize = sizeof (SCROLLINFO);
infoH.fMask = SIF_PAGE;
infoH.nPage = BAR_SIZE;
m_hScrollBar.SetScrollInfo (&infoH);
SCROLLINFO infoV;
infoV.cbSize = sizeof (SCROLLINFO);
infoV.fMask = SIF_PAGE;
infoV.nPage = BAR_SIZE;
m_vScrollBar.SetScrollInfo (&infoV);
//滑塊大小
}
else
{
m_hScrollBar.SetScrollPos (0);
m_hScrollBar.ShowWindow (SW_HIDE);
m_vScrollBar.SetScrollPos (0);
m_vScrollBar.ShowWindow (SW_HIDE);
}
RefreshSrcView ();
return CDialogEx::OnMouseWheel (nFlags, zDelta, pt);
}
I have a Python code (for implementing RayTracing) that I'm running in parallel with PyCuda.
import pycuda.driver as drv
import pycuda.autoinit
from pycuda.compiler import SourceModule
import numpy as np
from stl import mesh
import time
my_mesh = mesh.Mesh.from_file('test_solid_py.stl')
n = my_mesh.normals
v0 = my_mesh.v0
v1 = my_mesh.v1
v2 = my_mesh.v2
v0_x = v0[:,0]
v0_x = np.ascontiguousarray(v0_x)
v0_y = v0[:,1]
v0_y = np.ascontiguousarray(v0_y)
v0_z = v0[:,2]
v0_z = np.ascontiguousarray(v0_z)
v1_x = v1[:,0]
v1_x = np.ascontiguousarray(v1_x)
v1_y = v1[:,1]
v1_y = np.ascontiguousarray(v1_y)
v1_z = v1[:,2]
v1_z = np.ascontiguousarray(v1_z)
v2_x = v2[:,0]
v2_x = np.ascontiguousarray(v2_x)
v2_y = v2[:,1]
v2_y = np.ascontiguousarray(v2_y)
v2_z = v2[:,2]
v2_z = np.ascontiguousarray(v2_z)
mod = SourceModule("""
#include <math.h>
__global__ void intersect(float *origin,float *dir_x,float *dir_y,float *dir_z,float *v0_x,float *v0_y,float *v0_z,float *v1_x,float *v1_y,float *v1_z,float *v2_x,float *v2_y,float *v2_z,float *int_point_real_x, float *int_point_real_y,float *int_point_real_z)
{
using namespace std;
unsigned int idx = blockDim.x*blockIdx.x + threadIdx.x;
int count = 0;
float v0_current[3];
float v1_current[3];
float v2_current[3];
float dir_current[3] = {dir_x[idx],dir_y[idx],dir_z[idx]};
float int_point[3];
float int_pointS[2][3];
int int_faces[2];
float dist[2];
dist[0] = -999;
int n_tri = 105500;
for(int i = 0; i<n_tri; i++) {
v0_current[0] = v0_x[i];
v0_current[1] = v0_y[i];
v0_current[2] = v0_z[i];
v1_current[0] = v1_x[i];
v1_current[1] = v1_y[i];
v1_current[2] = v1_z[i];
v2_current[0] = v2_x[i];
v2_current[1] = v2_y[i];
v2_current[2] = v2_z[i];
double eps = 0.0000001;
float E1[3];
float E2[3];
float s[3];
for (int j = 0; j < 3; j++) {
E1[j] = v1_current[j] - v0_current[j];
E2[j] = v2_current[j] - v0_current[j];
s[j] = origin[j] - v0_current[j];
}
float h[3];
h[0] = dir_current[1] * E2[2] - dir_current[2] * E2[1];
h[1] = -(dir_current[0] * E2[2] - dir_current[2] * E2[0]);
h[2] = dir_current[0] * E2[1] - dir_current[1] * E2[0];
float a;
a = E1[0] * h[0] + E1[1] * h[1] + E1[2] * h[2];
if (a > -eps && a < eps) {
int_point[0] = false;
}
else {
double f = 1 / a;
float u;
u = f * (s[0] * h[0] + s[1] * h[1] + s[2] * h[2]);
if (u < 0 || u > 1) {
int_point[0] = false;
}
else {
float q[3];
q[0] = s[1] * E1[2] - s[2] * E1[1];
q[1] = -(s[0] * E1[2] - s[2] * E1[0]);
q[2] = s[0] * E1[1] - s[1] * E1[0];
float v;
v = f * (dir_current[0] * q[0] + dir_current[1] * q[1] + dir_current[2] * q[2]);
if (v < 0 || (u + v)>1) {
int_point[0] = false;
}
else {
float t;
t = f * (E2[0] * q[0] + E2[1] * q[1] + E2[2] * q[2]);
if (t > eps) {
for (int j = 0; j < 3; j++) {
int_point[j] = origin[j] + dir_current[j] * t;
}
//return t;
}
}
}
}
if (int_point[0] != false) {
count = count+1;
int_faces[count-1] = i;
dist[count-1] = sqrt(pow((origin[0] - int_point[0]), 2) + pow((origin[1] - int_point[1]), 2) + pow((origin[2] - int_point[2]), 2));
for (int j = 0; j<3; j++) {
int_pointS[count-1][j] = int_point[j];
}
}
}
double min = dist[0];
int ind_min = 0;
for (int i = 0; i < 2; i++){
if (min > dist[i]) {
min = dist[i];
ind_min = i;
}
}
if (dist[0] < -998){
int_point_real_x[idx] = -999;
int_point_real_y[idx] = -999;
int_point_real_z[idx] = -999;
}
else{
int_point_real_x[idx] = int_pointS[ind_min][0];
int_point_real_y[idx] = int_pointS[ind_min][1];
int_point_real_z[idx] = int_pointS[ind_min][2];
}
}
""")
n_rays = 20000
num_threads = 1024
num_blocks = int(n_rays/num_threads)
origin = np.asarray([-2, -2, -2]).astype(np.float32)
origin = np.ascontiguousarray(origin)
rand_x = np.random.randn(n_rays)
rand_y = np.random.randn(n_rays)
rand_z = np.random.randn(n_rays)
direction_x = np.ones((n_rays, 1)) * 3
direction_x = direction_x.astype(np.float32)
direction_x = np.ascontiguousarray(direction_x)
direction_y = np.ones((n_rays, 1)) * 4
direction_y = direction_y.astype(np.float32)
direction_y = np.ascontiguousarray(direction_y)
direction_z = np.ones((n_rays, 1)) * 5
direction_z = direction_z.astype(np.float32)
direction_z = np.ascontiguousarray(direction_z)
int_point_real_x = np.zeros((n_rays, 1)).astype(np.float32)
int_point_real_x = np.ascontiguousarray(int_point_real_x)
int_point_real_y = np.zeros((n_rays, 1)).astype(np.float32)
int_point_real_y = np.ascontiguousarray(int_point_real_y)
int_point_real_z = np.zeros((n_rays, 1)).astype(np.float32)
int_point_real_z = np.ascontiguousarray(int_point_real_z)
intersect = mod.get_function("intersect")
start = time.time()
intersect(drv.In(origin), drv.In(direction_x),drv.In(direction_y),drv.In(direction_z),drv.In(v0_x),drv.In(v0_y),drv.In(v0_z), drv.In(v1_x),drv.In(v1_y),drv.In(v1_z), drv.In(v2_x), drv.In(v2_y), drv.In(v2_z), drv.Out(int_point_real_x),drv.Out(int_point_real_y),drv.Out(int_point_real_z), block=(num_threads, 1, 1), grid=((num_blocks+0), 1, 1))
finish = time.time()
print(finish-start)
I give as input some arrays whose size is 20k (dir_x, dir_y, dir_z) and I have as output 3 arrays (int_point_real_x,int_point_real_y,int_point_real_z) that have the same size as the above mentioned arrays (20k).
If n_rays is a multiple of num_threads, e.g. n_rays=19456 and num_threads=1024, then int_point_real_x_y_z are correctly filled by the kernel.
Otherwise, if n_rays is NOT a multiple of num_threads, e.g. n_rays=20000 (what I really need) and num_threads=1024, then int_point_real_x_y_z are filled by the kernel up to position 19455 and the 544 spots left in the array are not filled.
Does anyone know if this is a rule of CUDA?
If it's not, how could I modify my code in order to use an arbitrary size of input array (and not only multiple of num_threads)?
Thanks
your int(n_rays/num_threads) is rounding down
to fix this, you need to round up and then put a condition into the kernel to enforce that idx is valid and "do nothing" if it's not. this will cause some cores to waste time, but your code looks pretty suboptimal anyway so it probably won't matter much
I am using OpenCV and Python. I am trying to draw the longest line inside a contours.
I have a contour named cnt. The image is binary, the inside of the contours is white and the outside is black. I would like to draw the longest line inside the white contours. I found how to draw lines using cv2.lines but I didn't find how to draw the longest one. Do you have any ideas?
img_copy = cv2.dilate(copy.deepcopy(img), np.ones((2,2),np.uint8),iterations = 2)
contours, hierarchy = cv2.findContours(copy.deepcopy(img_copy),cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
areas = [cv2.contourArea(c) for c in contours]
max_index = np.argmax(areas)
cnt = contours[max_index]
The below method using to draw the number of number of lines from the image and get the degree of max value try this. its working fine
Mat Compute_skewAngle (Mat& src,Mat& src_gray,int drawLine) {
int thresh = 100;
RNG rng(12345);
// 1. Load Gray Scae Image
// 2. Get Size of Image
cv::Size size = src_gray.size();
// 3. blur the Grayscale image
cv::blur(src_gray, src_gray, cv::Size(3,3) );
cv::Mat threshold_output;
std::vector<std::vector<cv::Point> > contours;
std::vector<Vec4i> hierarchy;
// 4. Detect edges using Threshold / Canny edge Detector
//cv::threshold( src_gray, threshold_output, thresh, 255, THRESH_BINARY );
Mat dst, cdst;
cv::Canny(src_gray, dst, thresh, 200, 3);
// 5. Gray Image to BGR
cvtColor(dst, cdst, CV_GRAY2BGR);
#if 0
vector<Vec2f> lines;
HoughLines(dst, lines, 1, CV_PI/180, 100, 0, 0 );
for( size_t i = 0; i < lines.size(); i++ )
{
float rho = lines[i][0], theta = lines[i][1];
Point pt1, pt2;
double a = cos(theta), b = sin(theta);
double x0 = a*rho, y0 = b*rho;
pt1.x = cvRound(x0 + 1000*(-b));
pt1.y = cvRound(y0 + 1000*(a));
pt2.x = cvRound(x0 - 1000*(-b));
pt2.y = cvRound(y0 - 1000*(a));
line( cdst, pt1, pt2, Scalar(0,0,255), 3, CV_AA);
}
#else
vector<Vec4i> lines;
double angle = 0.;
int countNegative = 0;
int countPositive =0;
HoughLinesP(dst, lines, 1, CV_PI/180, 100, 10, 100);
NSMutableDictionary *angleCountDict = [[NSMutableDictionary alloc] init];
for( size_t i = 0; i < lines.size(); i++ )
{
if(drawLine == 1) { // draw line while pass flag value 1
Vec4i l = lines[i];
line( cdst, cv::Point(l[0], l[1]), cv::Point(l[2], l[3]), Scalar(0,0,255), 3, CV_AA);
}
double delta_y = lines[i][3] - lines[i][1];
double delta_x = lines[i][2] - lines[i][0];
double currentAngle =atan2(delta_y,delta_x);
int angleAsDeg = abs(currentAngle * 180 / CV_PI);
NSString *_retValue = [angleCountDict objectForKey:[NSString stringWithFormat:#"%d", angleAsDeg]];
int angleCount = [_retValue intValue];
[angleCountDict setObject:[NSNumber numberWithInt:angleCount + 1] forKey:[NSString stringWithFormat:#"%d", angleAsDeg]];
double slope = delta_y / delta_x ; // find the slope to detect the angle " - " or " + "
if(slope < 0)
countNegative ++;
else
countPositive ++;
}
#endif
// sort the dictionary to get the largest value of degree count
NSArray *blockSortedKeys = [angleCountDict keysSortedByValueUsingComparator: ^(id obj1, id obj2) {
return [obj2 compare:obj1];
}];
NSString *degreeVal;
if([blockSortedKeys count] > 0)
degreeVal = [blockSortedKeys objectAtIndex:0];
angle = [degreeVal doubleValue];
if(countNegative > countPositive) {
angle = - angle;
}
Mat outPut;
outPut = rotateMatImage(src,angle,cdst);
return outPut;
}
I am using OpenCV and Python. I am trying to draw the longest line inside a contours.
I have a contour named cnt. The image is binary, the inside of the contours is white and the outside is black. I would like to draw the longest line inside the white contours. I found how to draw lines using cv2.lines but I didn't find how to draw the longest one. Do you have any ideas?
img_copy = cv2.dilate(copy.deepcopy(img), np.ones((2,2),np.uint8),iterations = 2)
contours, hierarchy = cv2.findContours(copy.deepcopy(img_copy),cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
areas = [cv2.contourArea(c) for c in contours]
max_index = np.argmax(areas)
cnt = contours[max_index]
The below method using to draw the number of number of lines from the image and get the degree of max value try this. its working fine
Mat Compute_skewAngle (Mat& src,Mat& src_gray,int drawLine) {
int thresh = 100;
RNG rng(12345);
// 1. Load Gray Scae Image
// 2. Get Size of Image
cv::Size size = src_gray.size();
// 3. blur the Grayscale image
cv::blur(src_gray, src_gray, cv::Size(3,3) );
cv::Mat threshold_output;
std::vector<std::vector<cv::Point> > contours;
std::vector<Vec4i> hierarchy;
// 4. Detect edges using Threshold / Canny edge Detector
//cv::threshold( src_gray, threshold_output, thresh, 255, THRESH_BINARY );
Mat dst, cdst;
cv::Canny(src_gray, dst, thresh, 200, 3);
// 5. Gray Image to BGR
cvtColor(dst, cdst, CV_GRAY2BGR);
#if 0
vector<Vec2f> lines;
HoughLines(dst, lines, 1, CV_PI/180, 100, 0, 0 );
for( size_t i = 0; i < lines.size(); i++ )
{
float rho = lines[i][0], theta = lines[i][1];
Point pt1, pt2;
double a = cos(theta), b = sin(theta);
double x0 = a*rho, y0 = b*rho;
pt1.x = cvRound(x0 + 1000*(-b));
pt1.y = cvRound(y0 + 1000*(a));
pt2.x = cvRound(x0 - 1000*(-b));
pt2.y = cvRound(y0 - 1000*(a));
line( cdst, pt1, pt2, Scalar(0,0,255), 3, CV_AA);
}
#else
vector<Vec4i> lines;
double angle = 0.;
int countNegative = 0;
int countPositive =0;
HoughLinesP(dst, lines, 1, CV_PI/180, 100, 10, 100);
NSMutableDictionary *angleCountDict = [[NSMutableDictionary alloc] init];
for( size_t i = 0; i < lines.size(); i++ )
{
if(drawLine == 1) { // draw line while pass flag value 1
Vec4i l = lines[i];
line( cdst, cv::Point(l[0], l[1]), cv::Point(l[2], l[3]), Scalar(0,0,255), 3, CV_AA);
}
double delta_y = lines[i][3] - lines[i][1];
double delta_x = lines[i][2] - lines[i][0];
double currentAngle =atan2(delta_y,delta_x);
int angleAsDeg = abs(currentAngle * 180 / CV_PI);
NSString *_retValue = [angleCountDict objectForKey:[NSString stringWithFormat:#"%d", angleAsDeg]];
int angleCount = [_retValue intValue];
[angleCountDict setObject:[NSNumber numberWithInt:angleCount + 1] forKey:[NSString stringWithFormat:#"%d", angleAsDeg]];
double slope = delta_y / delta_x ; // find the slope to detect the angle " - " or " + "
if(slope < 0)
countNegative ++;
else
countPositive ++;
}
#endif
// sort the dictionary to get the largest value of degree count
NSArray *blockSortedKeys = [angleCountDict keysSortedByValueUsingComparator: ^(id obj1, id obj2) {
return [obj2 compare:obj1];
}];
NSString *degreeVal;
if([blockSortedKeys count] > 0)
degreeVal = [blockSortedKeys objectAtIndex:0];
angle = [degreeVal doubleValue];
if(countNegative > countPositive) {
angle = - angle;
}
Mat outPut;
outPut = rotateMatImage(src,angle,cdst);
return outPut;
}
I have a python program which draws some ellipses into a window. The following python code is used w
from PyQt4.QtGui import *
def draw_ellipse(self, center, rad_x, rad_y, angle, color):
qp = QtGui.QPainter()
qp.begin(self)
qp.translate(center)
qp.rotate(math.degrees(angle))
qp.setPen(QtGui.QColor(color))
qp.drawEllipse(QPoint(0, 0), rad_x, rad_y)
qp.end()
As you can see my input parameters are center, rad_x, rad_y and angle. These parameters are read in from a text file.
I want to use the very same parameter file in a Matlab program. For that I need to know the implementation of drawEllipse, so that I can implement the very same functionality in Matlab.
Unfortunately I don't seem to find the source code for drawEllipse. I found this link with the following code:
03114 {
03115 #ifdef QT_DEBUG_DRAW
03116 if (qt_show_painter_debug_output)
03117 printf("QPainter::drawEllipse(), [%.2f,%.2f,%.2f,%.2f]\n", r.x(), r.y(), r.width(), r.height());
03118 #endif
03119
03120 if (!isActive())
03121 return;
03122 Q_D(QPainter);
03123 d->updateState(d->state);
03124
03125 QRectF rect(r.normalized());
03126
03127 if (rect.isEmpty())
03128 return;
03129
03130 if (d->state->emulationSpecifier) {
03131 if (d->state->emulationSpecifier == QPaintEngine::PrimitiveTransform
03132 && d->state->txop == QPainterPrivate::TxTranslate) {
03133 rect.translate(QPointF(d->state->matrix.dx(), d->state->matrix.dy()));
03134 } else {
03135 QPainterPath path;
03136 path.addEllipse(rect);
03137 d->draw_helper(path, QPainterPrivate::StrokeAndFillDraw);
03138 return;
03139 }
03140 }
03141
03142 d->engine->drawEllipse(rect);
03143 }
Which leads me to this code (QPainterPath.addEllipse):
01052 void QPainterPath::addEllipse(const QRectF &boundingRect)
01053 {
01054 #ifndef QT_NO_DEBUG
01055 if (qIsNan(boundingRect.x()) || qIsNan(boundingRect.y())
01056 || qIsNan(boundingRect.width()) || qIsNan(boundingRect.height()))
01057 qWarning("QPainterPath::addEllipse: Adding ellipse where a parameter is NaN, results are undefined");
01058 #endif
01059 if (boundingRect.isNull())
01060 return;
01061
01062 ensureData();
01063 detach();
01064
01065 Q_D(QPainterPath);
01066 d->elements.reserve(d->elements.size() + 13);
01067
01068 QPointF pts[12];
01069 int point_count;
01070 QPointF start = qt_curves_for_arc(boundingRect, 0, 360, pts, &point_count);
01071
01072 moveTo(start);
01073 cubicTo(pts[0], pts[1], pts[2]); // 0 -> 270
01074 cubicTo(pts[3], pts[4], pts[5]); // 270 -> 180
01075 cubicTo(pts[6], pts[7], pts[8]); // 180 -> 90
01076 cubicTo(pts[9], pts[10], pts[11]); // 90 - >0
01077 d_func()->require_moveTo = true;
01078 }
So let's go into qstroker_8cpp and look at qt_curves_for_arc:
00722 QPointF qt_curves_for_arc(const QRectF &rect, qreal startAngle, qreal sweepLength,
00723 QPointF *curves, int *point_count)
00724 {
00725 Q_ASSERT(point_count);
00726 Q_ASSERT(curves);
00727
00728 #ifndef QT_NO_DEBUG
00729 if (qIsNan(rect.x()) || qIsNan(rect.y()) || qIsNan(rect.width()) || qIsNan(rect.height())
00730 || qIsNan(startAngle) || qIsNan(sweepLength))
00731 qWarning("QPainterPath::arcTo: Adding arc where a parameter is NaN, results are undefined");
00732 #endif
00733 *point_count = 0;
00734
00735 if (rect.isNull()) {
00736 return QPointF();
00737 }
00738
00739 if (sweepLength > 360) sweepLength = 360;
00740 else if (sweepLength < -360) sweepLength = -360;
00741
00742 // Special case fast path
00743 if (startAngle == 0.0 && sweepLength == 360.0) {
00744 qreal x = rect.x();
00745 qreal y = rect.y();
00746
00747 qreal w = rect.width();
00748 qreal w2 = rect.width() / 2;
00749 qreal w2k = w2 * QT_PATH_KAPPA;
00750
00751 qreal h = rect.height();
00752 qreal h2 = rect.height() / 2;
00753 qreal h2k = h2 * QT_PATH_KAPPA;
00754
00755 // 0 -> 270 degrees
00756 curves[(*point_count)++] = QPointF(x + w, y + h2 + h2k);
00757 curves[(*point_count)++] = QPointF(x + w2 + w2k, y + h);
00758 curves[(*point_count)++] = QPointF(x + w2, y + h);
00759
00760 // 270 -> 180 degrees
00761 curves[(*point_count)++] = QPointF(x + w2 - w2k, y + h);
00762 curves[(*point_count)++] = QPointF(x, y + h2 + h2k);
00763 curves[(*point_count)++] = QPointF(x, y + h2);
00764
00765 // 180 -> 90 degrees
00766 curves[(*point_count)++] = QPointF(x, y + h2 - h2k);
00767 curves[(*point_count)++] = QPointF(x + w2 - w2k, y);
00768 curves[(*point_count)++] = QPointF(x + w2, y);
00769
00770 // 90 -> 0 degrees
00771 curves[(*point_count)++] = QPointF(x + w2 + w2k, y);
00772 curves[(*point_count)++] = QPointF(x + w, y + h2 - h2k);
00773 curves[(*point_count)++] = QPointF(x + w, y + h2);
00774
00775 return QPointF(x + w, y + h2);
00776 }
00777
00778 #define ANGLE(t) ((t) * 2 * Q_PI / 360.0)
00779 #define SIGN(t) (t > 0 ? 1 : -1)
00780 qreal a = rect.width() / 2.0;
00781 qreal b = rect.height() / 2.0;
00782
00783 qreal absSweepLength = (sweepLength < 0 ? -sweepLength : sweepLength);
00784 int iterations = (int)ceil((absSweepLength) / 90.0);
00785
00786 QPointF first_point;
00787
00788 if (iterations == 0) {
00789 first_point = rect.center() + QPointF(a * qCos(ANGLE(startAngle)),
00790 -b * qSin(ANGLE(startAngle)));
00791 } else {
00792 qreal clength = sweepLength / iterations;
00793 qreal cosangle1, sinangle1, cosangle2, sinangle2;
00794
00795 for (int i=0; i<iterations; ++i) {
00796 qreal cangle = startAngle + i * clength;
00797
00798 cosangle1 = qCos(ANGLE(cangle));
00799 sinangle1 = qSin(ANGLE(cangle));
00800 cosangle2 = qCos(ANGLE(cangle + clength));
00801 sinangle2 = qSin(ANGLE(cangle + clength));
00802
00803 // Find the start and end point of the curve.
00804 QPointF startPoint = rect.center() + QPointF(a * cosangle1, -b * sinangle1);
00805 QPointF endPoint = rect.center() + QPointF(a * cosangle2, -b * sinangle2);
00806
00807 // The derived at the start and end point.
00808 qreal sdx = -a * sinangle1;
00809 qreal sdy = -b * cosangle1;
00810 qreal edx = -a * sinangle2;
00811 qreal edy = -b * cosangle2;
00812
00813 // Creating the tangent lines. We need to reverse their direction if the
00814 // sweep is negative (clockwise)
00815 QLineF controlLine1(startPoint, startPoint + SIGN(sweepLength) * QPointF(sdx, sdy));
00816 QLineF controlLine2(endPoint, endPoint - SIGN(sweepLength) * QPointF(edx, edy));
00817
00818 // We need to scale down the control lines to match that of the current sweeplength.
00819 // qAbs because we only want to scale, not change direction.
00820 qreal kappa = QT_PATH_KAPPA * qAbs(clength) / 90.0;
00821 // Adjust their length to fit the magic KAPPA length.
00822 controlLine1.setLength(controlLine1.length() * kappa);
00823 controlLine2.setLength(controlLine2.length() * kappa);
00824
00825 curves[(*point_count)++] = controlLine1.p2();
00826 curves[(*point_count)++] = controlLine2.p2();
00827 curves[(*point_count)++] = endPoint;
00828
00829 if (i == 0)
00830 first_point = startPoint;
00831 }
00832 }
00833
00834 return first_point;
00835 }
This is quite a lot of code for drawing a simple ellipse! It doesn't feel right to rewrite all of this in Matlab, if a simple ellipse can be plotted like this:
a = rad_x; % horizontal radius
b = rad_y; % vertical radius
x0 = center_x; % x0, y0 ellipse centre coordinates
y0 = center_y;
steps = 50;
t = linspace(0, 2*pi, steps);
theta0 = angle;
x = x0 + (a * sin(t - theta0));
y = y0 + (b * cos(t));
plot(x, y, '.-'),
Question:
given the four parameters listed above (center, rad_x, rad_y and angle), what's the easiest way for me to plot the ellipse correctly in matlab? With my matlab code above plotting currently only works for small angles and particular rad_x & rad_y combinations.
How about something like this?
a = rad_x;
b = rad_y;
r0 = center_x + i*center_y; % <-- origin of ellipse
theta0=angle; % <-- angle of rotation of ellipse
steps = 200;
t = linspace(0, 2*pi, steps);
r = a*sin(t) + i*b*cos(t);
R = exp(i*theta0);
r = R*r;
r = r0 + r;
figure(1), hold on
plot(real(r), imag(r), '-r')
Using matrices rather than complex numbers:
a = rad_x;
b = rad_y;
r0 = [center_x ; center_y]; % <-- origin of ellipse
theta0=angle; % <-- angle of rotation of ellipse
steps = 200;
t = linspace(0, 2*pi, steps);
r = [a*sin(t) ; b*cos(t)];
R = [cos(theta0) -sin(theta0) ; sin(theta0) cos(theta0)]; % <-- note neg signs: define direction of rotation!
r = R*r;
r = r0*ones(1,length(t)) + r;
figure(1)
plot(r(1,:), r(2,:), '-r')