You are hereFeed aggregator

Feed aggregator

  • warning: date(): It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected the timezone 'UTC' for now, but please set date.timezone to select your timezone. in /Users/thor/Sites/modules/aggregator/aggregator.pages.inc on line 259.
  • warning: date(): It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected the timezone 'UTC' for now, but please set date.timezone to select your timezone. in /Users/thor/Sites/modules/aggregator/aggregator.pages.inc on line 259.
  • warning: date(): It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected the timezone 'UTC' for now, but please set date.timezone to select your timezone. in /Users/thor/Sites/modules/aggregator/aggregator.pages.inc on line 259.
  • warning: date(): It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected the timezone 'UTC' for now, but please set date.timezone to select your timezone. in /Users/thor/Sites/modules/aggregator/aggregator.pages.inc on line 259.
  • warning: date(): It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected the timezone 'UTC' for now, but please set date.timezone to select your timezone. in /Users/thor/Sites/modules/aggregator/aggregator.pages.inc on line 259.
  • warning: date(): It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected the timezone 'UTC' for now, but please set date.timezone to select your timezone. in /Users/thor/Sites/modules/aggregator/aggregator.pages.inc on line 259.
  • warning: date(): It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected the timezone 'UTC' for now, but please set date.timezone to select your timezone. in /Users/thor/Sites/modules/aggregator/aggregator.pages.inc on line 259.
  • warning: date(): It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected the timezone 'UTC' for now, but please set date.timezone to select your timezone. in /Users/thor/Sites/modules/aggregator/aggregator.pages.inc on line 259.
  • warning: date(): It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected the timezone 'UTC' for now, but please set date.timezone to select your timezone. in /Users/thor/Sites/modules/aggregator/aggregator.pages.inc on line 259.
  • warning: date(): It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected the timezone 'UTC' for now, but please set date.timezone to select your timezone. in /Users/thor/Sites/modules/aggregator/aggregator.pages.inc on line 259.
  • warning: date(): It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected the timezone 'UTC' for now, but please set date.timezone to select your timezone. in /Users/thor/Sites/modules/aggregator/aggregator.pages.inc on line 259.
  • warning: date(): It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected the timezone 'UTC' for now, but please set date.timezone to select your timezone. in /Users/thor/Sites/modules/aggregator/aggregator.pages.inc on line 259.
  • warning: date(): It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected the timezone 'UTC' for now, but please set date.timezone to select your timezone. in /Users/thor/Sites/modules/aggregator/aggregator.pages.inc on line 259.
  • warning: date(): It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected the timezone 'UTC' for now, but please set date.timezone to select your timezone. in /Users/thor/Sites/modules/aggregator/aggregator.pages.inc on line 259.
  • warning: date(): It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected the timezone 'UTC' for now, but please set date.timezone to select your timezone. in /Users/thor/Sites/modules/aggregator/aggregator.pages.inc on line 259.
  • warning: date(): It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected the timezone 'UTC' for now, but please set date.timezone to select your timezone. in /Users/thor/Sites/modules/aggregator/aggregator.pages.inc on line 259.
  • warning: date(): It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected the timezone 'UTC' for now, but please set date.timezone to select your timezone. in /Users/thor/Sites/modules/aggregator/aggregator.pages.inc on line 259.
  • warning: date(): It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected the timezone 'UTC' for now, but please set date.timezone to select your timezone. in /Users/thor/Sites/modules/aggregator/aggregator.pages.inc on line 259.
  • warning: date(): It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected the timezone 'UTC' for now, but please set date.timezone to select your timezone. in /Users/thor/Sites/modules/aggregator/aggregator.pages.inc on line 259.
  • warning: date(): It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected the timezone 'UTC' for now, but please set date.timezone to select your timezone. in /Users/thor/Sites/modules/aggregator/aggregator.pages.inc on line 259.
  • warning: date(): It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected the timezone 'UTC' for now, but please set date.timezone to select your timezone. in /Users/thor/Sites/modules/aggregator/aggregator.pages.inc on line 259.
  • warning: date(): It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected the timezone 'UTC' for now, but please set date.timezone to select your timezone. in /Users/thor/Sites/modules/aggregator/aggregator.pages.inc on line 259.
  • warning: date(): It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected the timezone 'UTC' for now, but please set date.timezone to select your timezone. in /Users/thor/Sites/modules/aggregator/aggregator.pages.inc on line 259.
  • warning: date(): It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected the timezone 'UTC' for now, but please set date.timezone to select your timezone. in /Users/thor/Sites/modules/aggregator/aggregator.pages.inc on line 259.
  • warning: date(): It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected the timezone 'UTC' for now, but please set date.timezone to select your timezone. in /Users/thor/Sites/modules/aggregator/aggregator.pages.inc on line 259.
  • warning: date(): It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected the timezone 'UTC' for now, but please set date.timezone to select your timezone. in /Users/thor/Sites/modules/aggregator/aggregator.pages.inc on line 259.
  • warning: date(): It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected the timezone 'UTC' for now, but please set date.timezone to select your timezone. in /Users/thor/Sites/modules/aggregator/aggregator.pages.inc on line 259.
  • warning: date(): It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected the timezone 'UTC' for now, but please set date.timezone to select your timezone. in /Users/thor/Sites/modules/aggregator/aggregator.pages.inc on line 259.
  • warning: date(): It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected the timezone 'UTC' for now, but please set date.timezone to select your timezone. in /Users/thor/Sites/modules/aggregator/aggregator.pages.inc on line 259.
  • warning: date(): It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected the timezone 'UTC' for now, but please set date.timezone to select your timezone. in /Users/thor/Sites/modules/aggregator/aggregator.pages.inc on line 259.
  • warning: date(): It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected the timezone 'UTC' for now, but please set date.timezone to select your timezone. in /Users/thor/Sites/modules/aggregator/aggregator.pages.inc on line 259.
  • warning: date(): It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected the timezone 'UTC' for now, but please set date.timezone to select your timezone. in /Users/thor/Sites/modules/aggregator/aggregator.pages.inc on line 259.
  • warning: date(): It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected the timezone 'UTC' for now, but please set date.timezone to select your timezone. in /Users/thor/Sites/modules/aggregator/aggregator.pages.inc on line 259.
  • warning: date(): It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected the timezone 'UTC' for now, but please set date.timezone to select your timezone. in /Users/thor/Sites/modules/aggregator/aggregator.pages.inc on line 259.
  • warning: date(): It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected the timezone 'UTC' for now, but please set date.timezone to select your timezone. in /Users/thor/Sites/modules/aggregator/aggregator.pages.inc on line 259.
  • warning: date(): It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected the timezone 'UTC' for now, but please set date.timezone to select your timezone. in /Users/thor/Sites/modules/aggregator/aggregator.pages.inc on line 259.
  • warning: date(): It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected the timezone 'UTC' for now, but please set date.timezone to select your timezone. in /Users/thor/Sites/modules/aggregator/aggregator.pages.inc on line 259.
  • warning: date(): It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected the timezone 'UTC' for now, but please set date.timezone to select your timezone. in /Users/thor/Sites/modules/aggregator/aggregator.pages.inc on line 259.
  • warning: date(): It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected the timezone 'UTC' for now, but please set date.timezone to select your timezone. in /Users/thor/Sites/modules/aggregator/aggregator.pages.inc on line 259.
  • warning: date(): It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected the timezone 'UTC' for now, but please set date.timezone to select your timezone. in /Users/thor/Sites/modules/aggregator/aggregator.pages.inc on line 259.

Superpixel Posterization

Matlab Image processing blog - 2018, May 21 - 14:28

Today's blog post was inspired by an example written by my friend and Image Processing Toolbox developer, Alex Taylor. A few years back, Alex tinkered with using toolbox algorithms to achieve a pseudo-artistic "posterization" effect, like this:

imshow('eddins-horn-1000.png')

I thought the technique was cool and worth showing. I also noticed that the example uses several Image Processing Toolbox functions that haven't been in the product very long, including:

    rgb2lab

    lab2rgb

    imoverlay

    boundarymask

    superpixels

So I realized this would be a good chance to introduce you to some recent toolbox additions that you might not know about.

rgb2lab and lab2rgb

The two functions rgb2lab and lab2rgb were introduced in R2014b. They convert between an RGB space and the CIE L*a*b* space. You could perform this conversion previously using the functions makecform and applycform, but it was awkward. These functions support both sRGB and Adobe RGB (1998).

I have mentioned these functions in a couple of previous blog posts, including "Displaying a color gamut surface" and "Out-of-gamut colors."

boundarymask

The function boundarymask, added in R2016a, produces a binary image whose foreground pixels delineate either the boundaries between adjacent labels, if you give it a label matrix, or the boundaries between the foreground and background, if you give it a binary image. Here's an example.

I = imread('rice.png'); bw = imbinarize(I,'adaptive'); mask = boundarymask(bw); subplot(1,2,1) imshow(I) title('Original image') subplot(1,2,2) imshow(mask) title('Boundary mask') imoverlay

The function imoverlay, added in R2016a, is useful for highlighting a subset of pixel locations in an image. A good example would be to show the boundary mask computed above on top of the original image.

I_overlay = imoverlay(I,mask,'yellow'); imshow(I_overlay)

In my first year of writing this blog (2006), I wrote my own function with this name and submitted it to the File Exchange. Now that the Image Processing Toolbox has its own version, I'll probably remove mine from the File Exchange soon.

superpixels

A "superpixel" is simply a group of connected pixels that have similar colors. Computing superpixels has found a regular place in a variety of image analysis and computer vision tasks. The Image Processing Toolbox function superpixels, introduced in R2016a, computes these groups. Here's an example that computes the superpixels and then uses both boundarymask and imoverlay to visualize them.

A = imread('kobi.png'); L = superpixels(A,1500); mask = boundarymask(L); B = imoverlay(A,mask,'cyan'); clf imshow(B) Superpixel Posterization

The superpixel posterization method, as implemented by Alex, starts by using superpixels to compute clusters of like pixels.

Here's how it works.

A = imread('eddins-horn.png'); imshow(A) title('Original image')

Next, compute and visualize the superpixel clusters.

[L,N] = superpixels(A,1000); BW = boundarymask(L); imshow(imoverlay(A,BW,'cyan'))

In the next step, I want to replace the pixels in each superpixel cluster with the mean of the cluster's colors. But I want to compute the mean in L*a*b* space, so I start by converting from RGB to L*a*b*.

Alab = rgb2lab(A);

I'll use the function label2idx to compute the indices of the pixels in each superpixel cluster. That will let me access the red, green, and blue component values using linear indexing.

pixel_idx = label2idx(L);

For each of the N superpixel clusters, use linear indexing to access the red, green, and blue components, compute the corresponding means, and insert those mean values into the corresponding pixel positions in the L*a*b* output image.

Aplab = Alab; Ln = numel(L); for k = 1:N idx = pixel_idx{k}; Aplab(idx) = mean(Alab(idx)); Aplab(idx+Ln) = mean(Alab(idx+Ln)); Aplab(idx+2*Ln) = mean(Alab(idx+2*Ln)); end

Finally, convert back to RGB space.

Ap = lab2rgb(Aplab); imshow(Ap)

Categories: Blogs

Feret Properties – Wrapping Up

Matlab Image processing blog - 2018, April 17 - 11:11

Today I want to finish up my long-running discussion of Feret diameters. (Previous posts: 29-Sep-2017, 24-Oct-2017, 20-Feb-2018, and 16-Mar-2018.)

Recall that the Feret diameter measures the extent of an object along a particular direction. The diagram below illustrates the concept. Place the object to be measured inside the jaws of a caliper, with the caliper oriented at a specified angle. Close the jaws tightly on the object while maintaining that angle. The distance between the jaws is the Feret diameter at that angle.

The maximum Feret diameter and minimum Feret diameter measure the maximum and minimum width of an object. In previous posts, I talked about how to identify antipodal vertex pairs from the set the convex hull vertices to speed up the process of finding these maximum and minimum measures. I also considered the various assumptions one can make about the shape of an individual pixel and how those assumptions can affect the results. (In the rest of this post, I'll assume a diamond pixel shape, as suggested by Cris.)

Let's look at these several measurements for a particular object.

bw = imread('shape.png'); imshow(bw) visualizeFeretProperties(bw)

The first diagram above shows the maximum Feret diameter and its orientation. It also shows the Feret diameter at the angle that is orthogonal to the maximum diameter.

The second diagram is similar, except that it shows the minimum Feret diameter instead of the orthogonal diameter. You can see that they are not the same, and, in general, they won't be.

The third diagram shows the minimum-area bounding box, which can be found using a search procedure similar to the minimum Feret diameter. In this diagram, notice that the bounding box is not exactly aligned with the direction of the maximum Feret dimension. In general, they won't necessarily be aligned, and then the length of the minimum-area bounding box will be less than the maximum Feret dimension.

Below is a function I wrote that adds Feret diameter properties to the table returned by regionprops (using the 'table' option). It makes use of the algorithmic functions that you can find in my previous posts.

T = regionprops('table',bw,'PixelList') T=1×1 table PixelList _________________ [163875×2 double] T = feretProperties(T) T=1×12 table PixelList MaxFeretDiameter MaxFeretDiameterEndpoints MaxFeretDiameterOrientation MinFeretDiameter MinFeretDiameterTrianglePoints MinFeretDiameterOrientation OrthogonalDiameter OrthogonalDiameterLowerPoints OrthogonalDiameterUpperPoints MinAreaBoundingBox MinAreaBoundingBoxArea _________________ ________________ _________________________ ___________________________ ________________ ______________________________ ___________________________ __________________ _____________________________ _____________________________ __________________ ______________________ [163875×2 double] 781.13 [2×2 double] -41.835 317.08 [3×2 double] -143.8 331.18 [1×2 double] [1×2 double] [5×2 double] 2.4321e+05

I hope that at least a few of you enjoyed this diversion into algorithms associated with object shape measurement.

Appendix: Functions Usedfunction T = feretProperties(T) % Copyright 2017-2018 The MathWorks, Inc. maxfd = zeros(height(T),1); maxfd_endpoints = cell(height(T),1); maxfd_orientation = zeros(height(T),1); minfd = zeros(height(T),1); minfd_triangle_points = cell(height(T),1); minfd_orientation = zeros(height(T),1); minod = zeros(height(T),1); minod_lower_points = cell(height(T),1); minod_upper_points = cell(height(T),1); minbb = cell(height(T),1); minbb_a = zeros(height(T),1); for k = 1:height(T) pixels = T.PixelList{k}; V = pixelHull(pixels,'diamond'); pairs = antipodalPairs(V); [maxfd(k),maxfd_endpoints{k}] = maxFeretDiameter(V,pairs); points = maxfd_endpoints{k}; e = points(2,:) - points(1,:); maxfd_orientation(k) = atan2d(e(2),e(1)); [minfd(k),minfd_triangle_points{k}] = minFeretDiameter(V,pairs); points = minfd_triangle_points{k}; e = points(2,:) - points(1,:); thetad = atan2d(e(2),e(1)); minfd_orientation(k) = mod(thetad + 180 + 90,360) - 180; [minod(k),minod_lower_points{k},minod_upper_points{k}] = ... feretDiameter(V,maxfd_orientation(k)+90); [minbb{k},minbb_a(k)] = minAreaBoundingBox(V,pairs); end T.MaxFeretDiameter = maxfd; T.MaxFeretDiameterEndpoints = maxfd_endpoints; T.MaxFeretDiameterOrientation = maxfd_orientation; T.MinFeretDiameter = minfd; T.MinFeretDiameterTrianglePoints = minfd_triangle_points; T.MinFeretDiameterOrientation = minfd_orientation; T.OrthogonalDiameter = minod; T.OrthogonalDiameterLowerPoints = minod_lower_points; T.OrthogonalDiameterUpperPoints = minod_upper_points; T.MinAreaBoundingBox = minbb; T.MinAreaBoundingBoxArea = minbb_a; end function [bb,A] = minAreaBoundingBox(V,antipodal_pairs) % Copyright 2017-2018 The MathWorks, Inc. if nargin < 2 antipodal_pairs = antipodalPairs(V); end n = size(antipodal_pairs,1); p = antipodal_pairs(:,1); q = antipodal_pairs(:,2); A = Inf; thetad = []; for k = 1:n if k == n k1 = 1; else k1 = k+1; end pt1 = []; pt2 = []; pt3 = []; if (p(k) ~= p(k1)) && (q(k) == q(k1)) pt1 = V(p(k),:); pt2 = V(p(k1),:); pt3 = V(q(k),:); elseif (p(k) == p(k1)) && (q(k) ~= q(k1)) pt1 = V(q(k),:); pt2 = V(q(k1),:); pt3 = V(p(k),:); end if ~isempty(pt1) % Points pt1, pt2, and pt3 are possibly on the minimum-area % bounding box, with points pt1 and pt2 forming an edge coincident with % the bounding box. Call the height of the triangle with base % pt1-pt2 the height of the bounding box, h. h = triangleHeight(pt1,pt2,pt3); pt1pt2_direction = atan2d(pt2(2)-pt1(2),pt2(1)-pt1(1)); w = feretDiameter(V,pt1pt2_direction); A_k = h*w; if (A_k < A) A = A_k; thetad = pt1pt2_direction; end end end % Rotate all the points so that pt1-pt2 for the minimum bounding box points % straight up. r = 90 - thetad; cr = cosd(r); sr = sind(r); R = [cr -sr; sr cr]; Vr = V * R'; xr = Vr(:,1); yr = Vr(:,2); xmin = min(xr); xmax = max(xr); ymin = min(yr); ymax = max(yr); bb = [ ... xmin ymin xmax ymin xmax ymax xmin ymax xmin ymin ]; % Rotate the bounding box points back. bb = bb * R; end function h = triangleHeight(P1,P2,P3) % Copyright 2017-2018 The MathWorks, Inc. h = 2 * abs(signedTriangleArea(P1,P2,P3)) / norm(P1 - P2); end function area = signedTriangleArea(A,B,C) % Copyright 2017-2018 The MathWorks, Inc. area = ( (B(1) - A(1)) * (C(2) - A(2)) - ... (B(2) - A(2)) * (C(1) - A(1)) ) / 2; end function [d,V1,V2] = feretDiameter(V,theta) % Copyright 2017-2018 The MathWorks, Inc. % Rotate points so that the direction of interest is vertical. alpha = 90 - theta; ca = cosd(alpha); sa = sind(alpha); R = [ca -sa; sa ca]; % Vr = (R * V')'; Vr = V * R'; y = Vr(:,2); ymin = min(y,[],1); ymax = max(y,[],1); d = ymax - ymin; if nargout > 1 V1 = V(y == ymin,:); V2 = V(y == ymax,:); end function [d,end_points] = maxFeretDiameter(P,antipodal_pairs) % Copyright 2017-2018 The MathWorks, Inc. if nargin < 2 antipodal_pairs = antipodalPairs(P); end v = P(antipodal_pairs(:,1),:) - P(antipodal_pairs(:,2),:); D = hypot(v(:,1),v(:,2)); [d,idx] = max(D,[],1); P1 = P(antipodal_pairs(idx,1),:); P2 = P(antipodal_pairs(idx,2),:); end_points = [P1 ; P2]; end function [d,triangle_points] = minFeretDiameter(V,antipodal_pairs) % Copyright 2017-2018 The MathWorks, Inc. if nargin < 2 antipodal_pairs = antipodalPairs(V); end n = size(antipodal_pairs,1); p = antipodal_pairs(:,1); q = antipodal_pairs(:,2); d = Inf; triangle_points = []; for k = 1:n if k == n k1 = 1; else k1 = k+1; end pt1 = []; pt2 = []; pt3 = []; if (p(k) ~= p(k1)) && (q(k) == q(k1)) pt1 = V(p(k),:); pt2 = V(p(k1),:); pt3 = V(q(k),:); elseif (p(k) == p(k1)) && (q(k) ~= q(k1)) pt1 = V(q(k),:); pt2 = V(q(k1),:); pt3 = V(p(k),:); end if ~isempty(pt1) % Points pt1, pt2, and pt3 form a possible minimum Feret diameter. % Points pt1 and pt2 form an edge parallel to caliper direction. % The Feret diameter orthogonal to the pt1-pt2 edge is the height % of the triangle with base pt1-pt2. d_k = triangleHeight(pt1,pt2,pt3); if d_k < d d = d_k; triangle_points = [pt1; pt2; pt3]; end end end end

Categories: Blogs

Talking Walkaway at Melbourne’s Wheeler Centre

Cory Doctorow - 2018, March 27 - 06:49

The Wheeler Centre just posted the audio (MP3) of my event there with C.S. Pacat, as part of my Australia/NZ book tour. It’s a great interview, and we had a lively Q&A!

Categories: Blogs

Podcast: The Man Who Sold the Moon, Part 07

Cory Doctorow - 2018, March 26 - 07:46


Here’s part seven of my reading (MP3) (part six, part five, part four, part three, part two, part one) of The Man Who Sold the Moon, my award-winning novella first published in 2015’s Hieroglyph: Stories and Visions for a Better Future, edited by Ed Finn and Kathryn Cramer. It’s my Burning Man/maker/first days of a better nation story and was a kind of practice run for my 2017 novel Walkaway.

MP3

Categories: Blogs

Podcast: The Man Who Sold the Moon, Part 06 [FIXED]

Cory Doctorow - 2018, March 18 - 07:25


Here’s part six of my reading (MP3) (part five, part four, part three, part two, part one) of The Man Who Sold the Moon, my award-winning novella first published in 2015’s Hieroglyph: Stories and Visions for a Better Future, edited by Ed Finn and Kathryn Cramer. It’s my Burning Man/maker/first days of a better nation story and was a kind of practice run for my 2017 novel Walkaway.

MP3

Categories: Blogs

Podcast: The Man Who Sold the Moon, Part 05 [FIXED]

Cory Doctorow - 2018, March 18 - 07:23


Here’s part five of my reading (MP3) (part four, part three, part two, part one) of The Man Who Sold the Moon, my award-winning novella first published in 2015’s Hieroglyph: Stories and Visions for a Better Future, edited by Ed Finn and Kathryn Cramer. It’s my Burning Man/maker/first days of a better nation story and was a kind of practice run for my 2017 novel Walkaway.

MP3

Categories: Blogs

Hugo nominations close tomorrow!

Cory Doctorow - 2018, March 15 - 09:59


If you attended either of the past two World Science Fiction Conventions or are registered for the next one in San Jose, California, you’re eligible to nominate for the Hugo Awards, which you can do here — you’ve only got until midnight tomorrow!


The 2017 Locus Recommended Reading List is a great place to start if you’re looking to refresh your memory about the sf/f you enjoyed last year.

May I humbly remind you that my novel Walkaway is eligible in the Best Novel category?

(via Scalzi)

Categories: Blogs

Classroom materials for Little Brother from Mary Kraus

Cory Doctorow - 2018, March 8 - 12:02

Mary Kraus — who created a key to page-numbers in the Little Brother audiobook for students with reading disabilities — continues to create great classroom materials for Little Brother: Who’s Who in “Little Brother” is a Quizlet that teaches about the famous people mentioned in the book, from Alan Turing to Rosa Luxembourg; while the Acronym Challenge asks students to unpack acronyms like DHS, NPR, IM, DNS, and ACLU.

Categories: Blogs

Hey, Wellington! I’m headed your way!

Cory Doctorow - 2018, March 6 - 16:26


I’ve just finished a wonderful time at the Adelaide Festival and now I’m headed to the last stop on the Australia/New Zealand tour for Walkaway: Wellington!


I’m doing a pair of events at Writers & Readers Week at the New Zealand Festival; followed by a special one-day NetHui on copyright and then a luncheon seminar for the Privacy Commissioner on “machine learning, big data and being less wrong.”

It starts on the 9th of March and finishes on the 13th, and I really hope I see you there! Thanks to everyone who’s come out in Perth, Sydney, Melbourne and Adelaide; you’ve truly made this a tour to remember.

Categories: Blogs

How to be better at being pissed off at Big Tech

Cory Doctorow - 2018, March 5 - 15:59

My latest Locus column, “Let’s Get Better at Demanding Better from Tech,” looks at how science fiction can make us better critics of technology by imagining how tech could be used in difference social and economic contexts than the one we live in today.

The “pro-tech” side’s argument is some variation on, “You can’t get the social benefits of Facebook without letting us spy on you and manipulate you — if you want to stay in touch with your friends, that’s the price of admission.” All too often, the “anti-tech” side takes this premise at face value: “Since we can’t hang out with our friends online without being spied on and manipulated, you need to stop wanting to hang out with your friends online.”

But the science fiction version of this goes, “What kinds of systems could we build if we wanted to hang out with our friends without being spied on and manipulated — and what kinds of political, regulatory and technological interventions would make those systems easier to build?”


A critique of technology that focuses on its market conditions, rather than its code, yields up some interesting alternate narratives. It has become fashionable, for example, to say that advertising was the original sin of online publication. Once the norm emerged that creative work would be free and paid for through attention – that is, by showing ads – the wheels were set in motion, leading to clickbait, political polarization, and invasive, surveillant networks: “If you’re not paying for the product, you’re the product.”

But if we understand the contours of the advertising marketplace as being driven by market conditions, not “attention economics,” a different story emerges. Market conditions have driven incredible consolidation in every sector of the economy, meaning that fewer and fewer advertisers call the shots, and meaning that more and more of the money flows through fewer and fewer payment processors. Compound that with lax anti-trust enforcement, and you have companies that are poised to put pressure on publishers and control who sees which information.

In 2018, companies from John Deere to GM to Johnson & Johnson use digital locks and abusive license agreements to force you to submit to surveillance and control how you use their products. It’s true that if you don’t pay for the product, you’re the product – but if you’re a farmer who’s just shelled out $500,000 for a new tractor, you’re still the product.

The “original sin of advertising” story says that if only microtransactions had been technologically viable and commercially attractive, we could have had an attention-respecting, artist-compensating online world, but in a world of mass inequality, financializing culture and discourse means excluding huge swaths of the population from the modern public sphere. If the Supreme Court’s Citizens United decision has you convinced that money has had a corrupting influence on who gets to speak, imagine how corrupting the situation would be if you also had to pay to listen.

Let’s Get Better at Demanding Better from Tech [Cory Doctorow/Locus]

Categories: Blogs

A key to page-numbers in the Little Brother audiobook

Cory Doctorow - 2018, March 2 - 18:34


Mary Kraus teaches my novel Little Brother to health science interns learning about cybersecurity; to help a student who has a print disability, Mary created a key that maps the MP3 files in the audiobook to the Tor paperback edition. She was kind enough to make her doc public to help other people move easily from the audiobook to the print edition — thanks, Mary!

Categories: Blogs

I’m coming to the Adelaide Festival this weekend (and then to Wellington, NZ!)

Cory Doctorow - 2018, March 2 - 15:30

I’m on the last two cities in my Australia/NZ tour for my novel Walkaway: today, I’m flying to Adelaide for the Adelaide Festival, where I’m appearing in several program items: Breakfast with Papers on Sunday at 8AM; a book signing on Monday at 10AM in Dymocks at Rundle Mall; “Dust Devils,” a panel followed by a signing on Monday at 5PM on the West Stage at Pioneer Women’s Memorial Garden; and “Craphound,” a panel/signing on Tuesday at 5PM on the East Stage at Pioneer Women’s Memorial Garden.


After Adelaide, I’m off to Wellington for Writers and Readers Week and then the NetHui one-day copyright event.

I’ve had a fantastic time in Perth, Melbourne and Sydney and it’s been such a treat to meet so many of you — I’m looking so forward to these last two stops!

Categories: Blogs

Hey, Sydney! I’m coming to see you tonight (then Adelaide and Wellington!)

Cory Doctorow - 2018, February 28 - 13:53

I’m just about to go to the airport to fly to Sydney for tonight’s event, What should we do about Democracy?


It’s part of the Australia/New Zealand tour for Walkaway, and from Sydney, I’m moving on to the Adelaide Festival and then to Wellington for Writers and Readers Week and the NetHui one-day event on copyright.


It feels like democracy is under siege, even in rich, peaceful countries like Australia that have escaped financial shocks and civil strife. Populist impulses have been unleashed in the UK and USA. There is a record lack of trust in the institutions of politics and government, exacerbated by the ways in which social media and digital technology can spread ‘fake news’ and are being harnessed by foreign powers to meddle in politics. Important issues that citizens care about, like climate change, are sidelined by professional politicians, enhancing the appeal of outsider figures. Do these problems add up to the failure of democracy? Are Brexit and Trump outliers, or the new normal? Join a lively panel of experts and commentators explore some big questions about the future of democracy, and think more clearly about what we ought to do.

Speakers Cory Doctorow, A.C. Grayling, Rebecca Huntley and Lenore Taylor

Chair Jeremy Moss

Categories: Blogs

My short story about better cities, where networks give us the freedom to schedule our lives to avoid heat-waves and traffic jams

Cory Doctorow - 2018, February 28 - 13:47




I was lucky enough to be invited to submit a piece to Ian Bogost’s Atlantic series on the future of cities (previously: James Bridle, Bruce Sterling, Molly Sauter, Adam Greenfield); I told Ian I wanted to build on my 2017 Locus column about using networks to allow us to coordinate our work and play in a way that maximized our freedom, so that we could work outdoors on nice days, or commute when the traffic was light, or just throw an impromptu block party when the neighborhood needed a break.


The story is out today, with a gorgeous illustration by Molly Crabapple; the Atlantic called it “The City of Coordinated Leisure,” but in my heart it will always be “Coase’s Day Off: a microeconomics of coordinated leisure.”


There had been some block parties on Lima Street when Arturo had been too small to remember them, but then there had been a long stretch of unreasonably seasonable weather and no one had tried it, not until the year before, on April 18, a Thursday after a succession of days that vied to top each other for inhumane conditions, the weather app on the hallway wall showing 112 degrees before breakfast.

Mr. Papazian was the block captain for that party, and the first they’d known of it was when Arturo’s dad called out to his mom that Papazian had messaged them about a block party, and there was something funny in Dad’s tone, a weird mix of it’s so crazy and let’s do it.

That had been a day to remember, and Arturo had remembered, and watched the temperature.


The City of Coordinated Leisure [Cory Doctorow/The Atlantic]

Categories: Blogs

Podcast: The Man Who Sold the Moon, Part 05

Cory Doctorow - 2018, February 26 - 05:01


Here’s part five of my reading (MP3) (part four, part three, part two, part one) of The Man Who Sold the Moon, my award-winning novella first published in 2015’s Hieroglyph: Stories and Visions for a Better Future, edited by Ed Finn and Kathryn Cramer. It’s my Burning Man/maker/first days of a better nation story and was a kind of practice run for my 2017 novel Walkaway.

MP3

Categories: Blogs

Do We Need a New Internet?

Cory Doctorow - 2018, February 15 - 14:35

I was one of the interview subjects on an episode of BBC’s Tomorrow’s World called Do We Need a New Internet? (MP3); it’s a fascinating documentary, including some very thoughtful commentary from Edward Snowden.

Categories: Blogs

The 2018 Locus Poll is open: choose your favorite science fiction of 2017!

Cory Doctorow - 2018, February 15 - 12:08


Following the publication of its editorial board’s long-list of the best science fiction of 2017, science fiction publishing trade-journal Locus now invites its readers to vote for their favorites in the annual Locus Award. I’m honored to have won this award in the past, and doubly honored to see my novel Walkaway on the short list, and in very excellent company indeed.

While you’re thinking about your Locus List picks, you might also use the list as an aide-memoire in picking your nominees for the Hugo Awards.

Categories: Blogs

The Man Who Sold the Moon, Part 04 [FIXED]

Cory Doctorow - 2018, February 12 - 22:03


Here’s part four of my reading (MP3) (part three, part two, part one) of The Man Who Sold the Moon, my award-winning novella first published in 2015’s Hieroglyph: Stories and Visions for a Better Future, edited by Ed Finn and Kathryn Cramer. It’s my Burning Man/maker/first days of a better nation story and was a kind of practice run for my 2017 novel Walkaway.

MP3

Categories: Blogs

Hey, Australia and New Zealand, I’m coming to visit you!

Cory Doctorow - 2018, February 11 - 17:05

I’m about to embark on a tour of Australia and New Zealand to support my novel Walkaway, with stops in Perth, Melbourne, Sydney, Adelaide, and Wellington! I really hope you’ll come out and say hello!

Perth: Feb 24-25, Perth Festival

Melbourne: Feb 27: An expansive conversation about the imperfect present and foreseeable future with CS Pascat, St Kilda Town Hall, 19h

Melbourne: Feb 28: How do writers get paid?, Wheeler Centre, 1815h

Sydney: Mar 1: What should we do about democracy?, City Recital Hall, 1930h

Adelaide: Mar 4-6: Adelaide Festival


Wellington: Mar 9-11: Writers and Readers Week

Wellington: Mar 12: NetHui one-day event on copyright

Categories: Blogs

HomePod + Android #ForbiddenLove

DVD Jon - 2018, February 9 - 18:29

14 years… It’s hard to believe, but that’s how long it’s been since Apple introduced AirPlay audio streaming (originally called AirTunes) with the release of the first AirPort Express. From Apple’s press release in 2004:

AirTunes is Apple’s breakthrough music networking technology which works seamlessly with iTunes running on either Macs or PCs to let users easily create a wireless music network in their home. iTunes 4.6 automatically detects remote speakers and displays them in a simple pop-up list for the user to select. Once the remote speakers are selected, AirTunes wirelessly streams the iTunes music from the computer to the AirPort Express base station. AirTunes music is encoded to protect it from theft while streaming across the wireless music network and uses Apple’s lossless compression technology to ensure no loss of sound quality.

Shorty after the public release, I reverse engineered the AirTunes protocol and the key used to encrypt the audio stream and released JustePort, an open source AirTunes client.

When Apple in 2010 released iOS 4.2 with support for sending video to the 2nd gen Apple TV, they renamed AirTunes to AirPlay.

Since I co-founded doubleTwist a decade ago, we’ve been at the forefront of restoring digital media interoperability for users trapped in walled gardens. On Android we’ve supported AirPlay since 2011 and we currently support all three major protocols (AirPlay, Chromecast and DLNA). Whether you prefer to store your music locally or in a cloud service like OneDrive or Google Drive, we’ve got you covered with doubleTwist Player and CloudPlayer.

Like many others, we’ve been eagerly awaiting the launch of Apple’s first AirPlay speaker. We got our hands on the HomePod today for some testing and everything works flawlessly. Anything you can play in the doubleTwist apps (local music, cloud music, podcasts, radio) can be streamed to the HomePod.

Currently streaming my lossless music collection stored on Microsoft OneDrive to the Apple HomePod using my Google Pixel XL – sounds amazing!


Categories: Blogs