I am trying to write a program to print a circle of given diameter in Berkeley logo. I get the input diameter from the user of the program and draw a circle accordingly. But I do not know of any method to display a circle given the diameter. All along I have been using,
repeat 36 [fd 10 rt 10]
to draw a circle. But it is not what I want. I tried using formulas for diameter, but it is not working. Can anybody please help?
You have to find the perimeter first, then divide it by the total number of rotations, then set that as the value of forward in your loop.
E.g.
make "d 100
make "p 3.141592654*:d
make "i :p/36
repeat 36[fd :i rt 10]
you can have all of them in a single statement as
repeat 36[fd 3.141592654*:d/36 rt 10]
where d is the accepted value of the diameter
Related
I have two images and I need to place the second image inside the first image. The second image can be resized, rotated or skewed such that it covers a larger area of the other images as possible. As an example, in the figure shown below, the green circle need to be placed inside the blue shape:
Here the green circle is transformed such that it covers a larger area. Another example is shown below:
Note that there may be some multiple results. However, any similar result is acceptable as shown in the above example.
How do I solve this problem?
Thanks in advance!
I tested the idea I mentioned earlier in the comments and the output is almost good. It may be better but it takes time. The final code was too much and it depends on one of my old personal projects, so I will not share. But I will explain step by step how I wrote such an algorithm. Note that I have tested the algorithm many times. Not yet 100% accurate.
for N times do this:
1. Copy from shape
2. Transform it randomly
3. Put the shape on the background
4-1. It is not acceptable if the shape exceeds the background. Go to
the first step.
4.2. Otherwise we will continue to step 5.
5. We calculate the length, width and number of shape pixels.
6. We keep a list of the best candidates and compare these three
parameters (W, H, Pixels) with the members of the list. If we
find a better item, we will save it.
I set the value of N to 5,000. The larger the number, the slower the algorithm runs, but the better the result.
You can use anything for Transform. Mirror, Rotate, Shear, Scale, Resize, etc. But I used warpPerspective for this one.
im1 = cv2.imread(sys.path[0]+'/Back.png')
im2 = cv2.imread(sys.path[0]+'/Shape.png')
bH, bW = im1.shape[:2]
sH, sW = im2.shape[:2]
# TopLeft, TopRight, BottomRight, BottomLeft of the shape
_inp = np.float32([[0, 0], [sW, 0], [sW, sH], [0, sH]])
cx = random.randint(5, sW-5)
ch = random.randint(5, sH-5)
o = 0
# Random transformed output
_out = np.float32([
[random.randint(-o, cx-1), random.randint(1-o, ch-1)],
[random.randint(cx+1, sW+o), random.randint(1-o, ch-1)],
[random.randint(cx+1, sW+o), random.randint(ch+1, sH+o)],
[random.randint(-o, cx-1), random.randint(ch+1, sH+o)]
])
# Transformed output
M = cv2.getPerspectiveTransform(_inp, _out)
t = cv2.warpPerspective(shape, M, (bH, bW))
You can use countNonZero to find the number of pixels and findContours and boundingRect to find the shape size.
def getSize(msk):
cnts, _ = cv2.findContours(msk, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
cnts.sort(key=lambda p: max(cv2.boundingRect(p)[2],cv2.boundingRect(p)[3]), reverse=True)
w,h=0,0
if(len(cnts)>0):
_, _, w, h = cv2.boundingRect(cnts[0])
pix = cv2.countNonZero(msk)
return pix, w, h
To find overlaping of back and shape you can do something like this:
make a mask from back and shape and use bitwise methods; Change this section according to the software you wrote. This is just an example :)
mskMix = cv2.bitwise_and(mskBack, mskShape)
mskMix = cv2.bitwise_xor(mskMix, mskShape)
isCandidate = not np.any(mskMix == 255)
For example this is not a candidate answer; This is because if you look closely at the image on the right, you will notice that the shape has exceeded the background.
I just tested the circle with 4 different backgrounds; And the results:
After 4879 Iterations:
After 1587 Iterations:
After 4621 Iterations:
After 4574 Iterations:
A few additional points. If you use a method like medianBlur to cover the noise in the Background mask and Shape mask, you may find a better solution.
I suggest you read about Evolutionary Computation, Metaheuristic and Soft Computing algorithms for better understanding of this algorithm :)
I am trying to visualize a time series data set on one plot as a pseudo 3d figure. However, I am having some trouble getting the filledcurves capability working properly. It seems to be adding an unwanted border at the "bottom" of my functions and I do not know how to fix this.
This is my current set up: I have nb_of_frames different files that I want to plot on one figure. Without the filledcurves option, I can do something like this
plot for [i=1:nb_of_frames] filename(i) u ($1):(50.0 * $2 + (11.0 - (i-1)*time_step)) w l linewidth 1.2 lt rgb "black" notitle
which produces a figure like this:
no fill options
Instead of doing this, I want to use the filledcurves option to bring my plots "forward" and highlight the function that is more "forward" which I try to do with:
plot for [i=1:nb_of_frames] filename(i) u ($1):(50. * $2 + (11. - (i-1)*time_step)) w filledcurves fc "white" fs solid 1.0 border lc "black" notitle
This produces a figure as follows:
This is very close to what I want, but it seems that the border option adds a line underneath the function which I do not want. I have tried several variants of with filledcurves y1=0.0 with different values of y1, but nothing seems to work.
Any help would be appreciated. Thank you for your time.
Here is another workaround for gnuplot 5.2.
Apparently, gnuplot closes the filled area from the last point back to the first point. Hence, if you specifiy border, then this line will also have a border which is undesired here (at least until gnuplot 5.4rc2 as #Ethan says).
A straightforward solution would be to plot the data with filledcurves without border and then again with lines. However, since this is a series of shifted data, this has to be plotted alternately. Unfortunately, gnuplot cannot switch plotting styles within a for loop (at least I don't know how). As a workaround for this, you have to build your plot command in a previous loop and use it with a macro # (check help macros) in the plot command. I hope you can adapt the example below to your needs.
Code:
### filledcurves without bottom border
reset session
set colorsequence classic
$Data <<EOD
1 0
2 1
3 2
4 1
5 4
6 5
7 2
8 1
9 0
EOD
myData(i) = sprintf('$Data u ($1-0.1*%d):($2+%d/5.)',i,i)
myFill = ' w filledcurves fc "0xffdddd" fs solid 1 notitle'
myLine = ' w l lc rgb "black" notitle'
myPlotCmd = ''
do for [i=11:1:-1] {
myPlotCmd = myPlotCmd.myData(i).myFill.", ".myData(i).myLine.", "
}
plot #myPlotCmd
### end of code
Result:
I can reproduce this in gnuplot 5.2.8 but not in the output from the release candidate for version 5.4. So I think that some bug-fix or change was applied during the past year or so. I realize that doesn't help while you are using verion 5.2, but if you can download and build from source for the 5.4 release candidate that would take care of it.
Update
I thought of a work-around, although it may be too complicated to be worth it.
You can treat this as a 2D projection of a 3D fence plot constructed using plot style with zerrorfill. In this projection the y coordinate is the visual depth. X is X. Three quantities are needed on z: the bounding line, the bottom, and the top. I.e. 5 fields in the using clause: x depth zline zbase ztop.
unset key
set view 90, 180
set xyplane at 0
unset ytics
set title "3D projection into the xz plane\nplot with zerrorfill" offset 0,-2
set xlabel "X axis" offset 0,-1
set zlabel "Z"
splot for [i=1:25] 'foo.dat' using ($1+i):(i/100.):($2-i):(-i):($2-i) \
with zerrorfill fc "light-cyan" lc "black" lw 2
Scenario: I need to draw a plot that has a background image. Based on the information on that image there have to be multiple origins (let's call them 'targets') that can move over time. The movements of these targets will have to be indicated by arrows/vectors where the first vector originates at the location of the target, the second vector originates where the previous vector ended and so on.
The result should look similar to this:
Plot with targets and movement vectors
While trying to implement this, i stumbled upon different questions:
I would use a chart with combined series: a Scatter plot to add the targets at exact x/y locations and a vector plot to insert the vectors. Would this be a correct way?
Since i want to set each vectors starting point to exact x/y coordinates i use rotationOrigin: 'start'. When i now change vectorLength to something other than 20 the vector is still shifted by 10 pixels (http://jsfiddle.net/Chop_Suey/cx35ptrh/) this looks like a bug to me. Can it be fixed or is there a workaround?
When i define a vector it looks like [x, y, length, direction]. But length is a relative unit that is calculated with some magic relative to the longest vector which is 20 (pixels) by default or whatever i set vectorLength to. Thus, the vectors are not connected and the space between them changes depending on plot size axes min/max). I actually want to corellate the length with the plot axis (which might be tricky since the x-axis and y-axis might have different scales). A workaround could be to add a redraw event and recalculate the vectors on every resize and set the vectorLength to the currently longest vector (which again can be calculated to correlate to the axes). This is very cumbersome and i would prefer to be able to set the vectors somehow like [x1, y1, x2, y2] where (x1/y2) denotes the starting- and (x2/y2) the ending-point of the vector. Is this possible somehow? any recommendations?
Since the background image is not just a decoration but relevant for the displayed data to make sense it should change when i zoom in. Is it possible to 'lock' the background image to the original plot min/max so that when i zoom in, the background image is also zoomed (image quality does not matter)?
Combining these two series shoudn't be problematic at all, and that will be the correct way, but it is necessary to change the prototype functions a bit for that the vectors will draw in a different way. Here is the example: https://jsfiddle.net/6vkjspoc/
There is probably the bug in this module and we will report it as new issue as soon as it is possible. However, we made the workaround (or fix) for that and now it's working well, what you can notice in example above.
Vector length is currently calculated using scale, namely - if vectorLength value is equal to 100 (for example), and vector series has two points which looks like that:
{
type: 'vector',
vectorLength: 100,
rotationOrigin: 'start',
data: [
[1, 50000, 1, 120],
[1, 50000, 2, -120]
]
}
Then the highest length of all points is taken and basing on it the scale is calculated for each point, so first one length is equal to 50, because the algorithm is point.length / lengthMax, what you can deduce from the code below:
H.seriesTypes.vector.prototype.arrow = function(point) {
var path,
fraction = point.length / this.lengthMax,
u = fraction * this.options.vectorLength / 20,
o = {
start: 10 * u,
center: 0,
end: -10 * u
}[this.options.rotationOrigin] || 0;
// The stem and the arrow head. Draw the arrow first with rotation 0,
// which is the arrow pointing down (vector from north to south).
path = [
'M', 0, 7 * u + o, // base of arrow
'L', -1.5 * u, 7 * u + o,
0, 10 * u + o,
1.5 * u, 7 * u + o,
0, 7 * u + o,
0, -10 * u + o // top
];
return path;
}
Regarding your question about defining start and end of a vector by two x, y values, you need to refactor entire series code, so that it won't use the vectorLength at all as like as scale, because you will define the points length. I suspect that will be very complex solution, so you can try to do it by yourself, and let me know about the results.
In order to make it works, you need to recalculate and update vectorLength of your vector series inside of chart.events.selection handler. Here is the example: https://jsfiddle.net/nh7b6qx9/
SCENARIO
I am working on an application that keeps track of blood glucose levels into a graph. On the graph there are "markings" (ex: -200mg) going in vertical order along the y axis on the right side of the screen and "hours" (ex: -12:00 PM) will be along the x axis on the bottom of the graph. I have to plot out little 'dots' to display what the blood glucose level was throughout the way.
ISSUE
I am trying to calculate how to position the 'dots' in the correct time and mg level and I'm having difficulty calculating the positions. I can access the "markings" and retrieve it's marking.center.x to indicate which 'Time Slot' (x axis) and the marking.center.y to indicate which 'MG Level' the 'dot' needs to go into. Problem is it isn't always exactly 12:00 PM or 200mg where it will need to be placed. In fact that would be very rare.
WHAT I NEED
Based on the following variables:
dot.mgLevel
The dot will already know where it needs to go based on the information retrieved from the medical device. It will know the time and mgLevel to assign itself.
marking.mgLevel
The markings will each have evenly distributed values that such as -100mg, -200mg, -300mg ect...
timemarking.timeslot
Each time marking on the bottom will each have evenly distributed times allocated every 30 min. Such as -12:00PM, -12:30PM, -1:00PM ect...
If the dot has a mg Level of 330mg and the closest marking on the mg Level is 300mg, then I need to be able to calculate how much further up the dot needs to move from 300 going towards the 400mg marker.
SO...
If the distance between the markings are 100pt and the dot's mgLevel is 330mg, then I know that I need to move the dot from the 300mg marking toward the 400mg marking by exactly 30pt. That's because it's simple math because the distance between the markings is 100. But in real life it isn't 100, so I need to be able to calculate this.
MY ULTIMATE QUESTION
Say distance between markings is 241 and each marking represents multiples of a hundred. Say my dot has a mgLevel of 412. How do I calculate how far I need to move the dot so that it will be in the correct place?
I THINK?
I think I need to make 241 equal 100%. But I need help.
Distance between markings is 241pt
Markings are multiples of 100mg
1mg will occupy 2.41pt. So 412mg will occupy (2.41 * 412) pt. To know how much to move for the next dot, take the difference in mg and multiply by 2.41.
In general, if distance between 2 markings in points is d, markings are multiples of m, and desired accuracy is k decimal places, 1mg will occupy g:
let divisor = pow(10.0, Double(k))
let g = round((d/m)*divisor) / divisor
I'm following this tutorial
The goal is to be able to spit out either:
a. the center of each labeled object
b. all pixels associated with each labeled object
in a way that I have an array of either 'a.' for each object, or 'b.' for each object
I'm really not sure how to go about this. Are there matlabl tools to help extract these set of pixels or centers - per - label?
Update
I did manage to circle 80% of what I wanted using reigionprops, however it doesn't capture label precisely, just sets a circle around them while capturing the background as well, is that really unavoidable? I'm just not sure how to access the set of pixel per each circled item.
r=regionprops(L, 'All'); imshow(imagergb); areas={r.Area}; Bboxes={r.BoundingBox};
for k=2:numel(r)
if areas{k}>50 && areas{k} < 1100
rectangle('Position',Bboxes{k}, 'LineWidth',1, 'EdgeColor','b', 'Curvature', [1 1]);
end
end
So what I'm trying to do is for example.
I thought it might just be
r = regionprops(L, 'PixelIdxList')
then
element1 = r(1).PixelIdxList
but couldn't figure out how to get the position of each pixel
I also tried
Z= bwlabel(L);
but imshow(Z==1) spits out all labels and imshow(Z==2) spits out background, all labels and background. couldn't test bwlabeln since I'm not exactly sure what to enter for r and c arguments.
Using regionprops(L, 'PixelIdxList') is correct. It gives you lists of pixel indices for each label. You can then convert them to [x,y] coordinates using (for the first label, for example)
[y,x] = ind2sub(size(L), r(1).PixelIdxList)
You can get label centers by using regionprops(L, 'Centroid'). This already gives you [x,y] coordinates for each label. Note that these are subpixel coordinates, so you may need to round them if you want to use them as indices.