One of the more robust approaches to generating curved polygons for large datasets is to use PostGIS with some sort of smoothing function. PostGIS 2.5 has Chaikin smoothing but I have not tried this out yet.
What has worked for me is using the custom function CreateCurve documented here and then creating a VIEW in PostGIS based on the virtual layer (SQL) approach I've posted about here
Here is one I have used successfully with PostGIS 2.3 (I think it was 2.3):
CREATE OR REPLACE VIEW layer_name_pca AS
SELECT
ogc_fid,
treeid,
n,
e,
s,
w,
CASE WHEN n = s AND n = e AND n = w
THEN ST_Buffer(geom,n)
ELSE st_makepolygon(st_curvetoline(createcurve(st_makeline(array[
st_translate(geom,0,greatest(N,0.2)),
st_translate(geom,0.6*greatest(E,0.2),0.6*greatest(N,0.2)),
st_translate(geom,greatest(E,0.2),0),
st_translate(geom,0.6*greatest(E,0.2),-0.6*greatest(S,0.2)),
st_translate(geom,0,-greatest(S,0.2)),
st_translate(geom,-0.6*greatest(W,0.2),-0.6*greatest(S,0.2)),
st_translate(geom,-greatest(W,0.2),0),
st_translate(geom,-0.6*greatest(W,0.2),0.6*greatest(N,0.2)),
st_translate(geom,0,greatest(N,0.2))]),70)))
END
AS geom
FROM layer_name WHERE n IS NOT NULL;
This VIEW can then be loaded into QGIS as a polygon and you can proceed to do further calculations (e.g. total non-overlapping canopy area, canopy area intersection with proposed building footprint, etc.)
It is dynamic and fast and generates actual polygons; none of the other solutions have really managed to do all three.