How to work with anti-alias on delphi firemonkey and android - android

I work on delphi xe7 with firemonkey and testing on android.
When i work on a device that have a normal resolution of 1 (scene.scale=1) then component like TRoundRect, TPie, etc produce ugly result because they are not anti-aliased (or the anti-alias is not visible by humain eyes). if i work on high definition device (scene.scale=2 for exemple), then it's not really a big problem because high definition compensate the problem.
So first question, is their any way to make theses component produce anti-alias graphic ?
also how to draw directly on the canvas an anti-aliased disque (with an image in it) ?
Now when i work on bitmap and on canvas, i notice that the FillText produce anti-aliasing result. this is in someway good for what i want previously (for disque) but a little disaster for text because it's make them "blur".
it's even worse when i do first Mybitmap.canvas.FillText => produce a little of antialias and then later i do MyPaintBox.canvas.DrawBitmap(MyBitmap) it's will add AGAIN more anti-alias ! the text will be very blur at the end :( it's sound crazy for me that
doing canvas.drawBitmap without any distorsion in the srcRec and destRect not copy the exact pixel from bitmap to the canvas :(
so it's their a way to :
Call canvas.FillText without any anti-alias or to configure the level of anti-alias.
Call canvas.DrawBitmap without any anti-alias at all ! pixel perfect copy from bitmap to the canvas
thanks by advance for your help !
some solutions i found todays (and theirs problems) :
I found a way how to make all the visual controls (troundrect, etc) with anti-aliasing : set Tform.quality to highQuality !
But now i m facing another very strong problem that i can not understand :(
maybe a bug in delphi so if someone can look at it i will be very thanks to him ...
when you need a canvas for the form it's created via
constructor TCanvasGpu.CreateFromWindow(...AQuality: TCanvasQuality)
and here the quality is taken from the MyForm.quality
now the problem is with TBITMAP :( same as previous when we need the canvas for the bitmap it's created via
constructor TCanvasGpu.CreateFromBitmap(....AQuality: TCanvasQuality=TCanvasQuality.SystemDefault)
but here the problem their is NO PROPERTY at all in the bitmap to setup the quality of the canvas :(
so i try this solution :
aBitmap := Tbitmap.Create(w,h);
try
aCanvas := TCanvasManager.CreateFromBitmap(ABitmap, TCanvasQuality.HighQuality);
Try
aCanvas.BeginScene;
try
aCanvas.Fill.Kind := TbrushKind.solid;
acanvas.Fill.Color := $ff000000;
aCanvas.FillRect(TRectF.Create(0, 0, w, h), w / 2, h / 2, ALLcorners, 1);
finally
aCanvas.EndScene;
end;
Finally
aCanvas.Free;
End;
....
and i was thinking i will have now on my bitmap the same antialiasing effect of what i have when i draw directly on the canvas of the form ? absolutely not, nothing change and i still have ugly round without any anti-aliasing :(
what i miss ??
EDIT:
The only option i found for now to remove the antialias is to make the bitmap 2x more bigger and reduce it after by 2x! crazy :( but the algorithme of reduction remove the aliased ... but the cost of all of this is that the speed become slow, especially when we know that all the graphic function must be done in the main thread :(
Now more i think more i say to myself that it's crazy to have a graphic library that not support multi-thread ! i can not believe that it's a requirement of openGL and i think now more and more that it's a bug or bad conception in delphi :(
Speaking about the previous point, even if openGL really required that all graphic routines must be done in the main thread (but really i doubt), i don't understand why delphi not offer on android another TcanvasClass (other than TcanvasGPU) that support multithread ! more crazy is that when you work with TCanvasGPU on Tbitmap, the result will be in any case (as you can see in my previous post) different from what you will have working with TCanvasGPU on the visual component !
now i m looking for function to work directly on pixels grids (old school), that will make me possible to work in multi-thread. but unfortunately their is not to much compatible with firemonley/android :(
to finish this is the function i use to draw my bitmap. but as this function must be call in the main thread, it's slow down my application (especially the scroll) ... so if you have any idea to make this more fast or multithread i take :)
function DrawAdvertBitmap: Tbitmap;
var aBitmapAliased: Tbitmap;
begin
aBitmapAliased := Tbitmap.Create(trunc(FWidth * fScreenScale) * 2, trunc(FHeight * fScreenScale) * 2);
try
aBitmapAliased.Canvas.BeginScene;
try
aBitmapAliased.canvas.Clear(0);
aBitmapAliased.canvas.Fill.Color := $ff000000;
aBitmapAliased.Canvas.Fill.Kind := TbrushKind.Solid;
aBitmapAliased.Canvas.FillRect(...);
aBitmapAliased.Canvas.Fill.Color := $ff333844;
aBitmapAliased.Canvas.Font.Family := 'Roboto-Bold';
aBitmapAliased.Canvas.Font.Size := 12 * fScreenScale * 2;
aBitmapAliased.Canvas.Font.Style := [TFontStyle.fsBold];
aBitmapAliased.Canvas.FillText(...);
finally
aBitmapAliased.Canvas.EndScene;
end;
//reduce by 2 to make antialiased
result := Tbitmap.Create(trunc(FWidth * fScreenScale), trunc(FHeight * fScreenScale));
try
result.Canvas.BeginScene;
try
result.Canvas.Clear(0);
result.Canvas.DrawBitmap(aBitmapAliased,...);
finally
result.Canvas.EndScene;
end;
except
result.Free;
raise;
end;
result.BitmapScale := fScreenScale;
finally
aBitmapAliased.free;
end;
end;

If we talk about Firemonkey:
TImage has the property "DisableInterpolation: boolean"
TForm has the property "Quality: TCanvasQuality = (SystemDefault, HighPerformance, HighQuality)" — it is works in design-time
Important to know:
Anti-aliasing is very expensive operation, this is disabled by default on mobile platforms.
The same anti-aliasing should be supported by the device. To Support multisampling the OpenGL must have GL_EXT_multisampled_render_to_texture property. If the device hardware does not support multisampling, the AA will not be.

If you are seeing weird anti-aliasing on some controls, I would recommend that you check that the controls do not have fractional position and size values, make sure to use trunc/round on the position or the GPU canvas uses some low-quality interpolation effect on top of any anti-aliasing.
If you plan to do per-pixel manual adjustments, I recommend that you use optimized color-conversion code (scanline <> TAlphaColor) as the built-in code is designed for clear code and not performance:
https://github.com/bLightZP/OptimizedDelphiFMXScanline
As for drawing anti-aliased circles with pictures in them, I found the easiest way is to generate an anti-aliased opacity map and apply it to a TImage's TBitmap. You can find code for generating an anti-aliased opacity map here:
https://github.com/bLightZP/AntiAliasedCircle

1. Use FMXNativeDraw by OneChen (Aone), - it's very simple, you even do not need to change your standard code for Canvas - need to add only 2 lines (IFDEF). It also supports TPath.
It works on 4 platoforms - Win, Mac, Android, iOS. But you need it only on mobile platforms, because antialiasing works on Win and Mac.
I use FMXNativeDraw in my mobile projects and it works very well!
Read this article first with google translate about FMXNativeDraw: http://www.cnblogs.com/onechen/p/6350096.html
Download:
https://github.com/OneChen/FMXNativeDraw
Btw if you're using PaintBox Canvas - work as usual.
If you need to draw on TBitmap Canvas - prepare Bitmap first:
if Scene <> nil then
lScale := Scene.GetSceneScale
else
lScale := 1;
fBitmap.BitmapScale := lScale;
fBitmap.SetSize(Ceil(Width * lScale), Ceil(Height * lScale) );
2. (optional)
Also use ZMaterialComponents, that is a wrapper for FMXNativeDraw (circle, rectangle, line etc). You can place these components on a FMX Form as standard TCircle and others.
https://github.com/rzaripov1990/ZMaterialComponents

Related

Opencv findContours in Android seems much slower than findContours in Python. Do you have any suggestion to improve algorithm speed?

it's the first time for me that I ask help here. I will try to be as precise as possible in my question.
I am trying to develop a shape detection app for Android.
I first identified the algorithm which works for my case playing with Python. Basically for each frame I do this:
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
mask = cv2.inRange(hsv, lower_color, upper_color)
contours, _ = cv2.findContours(mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
for cnt in contours:
#here I filter my results
by this algorithm I am able to run the analysis realtime on videos having a frame rate of 120fps.
So I tryied to implement the same algorithm on Android Studio, doing the following for each Frame:
Imgproc.cvtColor(frameInput, tempFrame, Imgproc.COLOR_BGR2HSV);
Core.inRange(tempFrame,lowColorRoi,highColorRoi,tempFrame);
List<MatOfPoint> contours1 = new ArrayList<MatOfPoint>();
Imgproc.findContours(tempFrame /*.clone()*/, contours1, new Mat(), Imgproc.RETR_TREE, Imgproc.CHAIN_APPROX_SIMPLE);
for(MatOfPoint c : contours1){
//here I filter my results
}
and I see that only the findContour function takes 5-600ms to be performed at each iteration (I noticed that it takes also more using tempFrame.clone()), allowing more or less to run the analysis with only 2fps.
This speed is not acceptable at all of course. Do you have any suggestion about how to improve this speed? 30-40fps would be already a good target for me.
I will really appreciate any help from you all. Many thanks in advance.
I would suggest trying to do your shape analysis on a lower resolution version of the image, if that is acceptable. I often see directly proportional timing with number of pixels of the image and the number of channels of the image - so if you can halve the width and height it could be a 4 times performance improvement. If that works, likely the first thing to do is a resize, then all subsequent calls have a smaller burden.
Next, be careful using OpenCV in Java/Kotlin because there is a definite cost to marshalling over the JNI interface. You could write the majority of your code in native C++, and then make just a single call across JNI to a C++ function that handles all of the shape analysis at once.

Why is the worldtoscreen() output for Windows correct and is wrong for Android

I created a multi-device firemonkey form which included one viewport3d ,one Cube and one camera.I want to make a calloutpanel exactly on the top of the cube in the form with camera projection.
In Firemonkey, we can use worldtoscreen() to convert absolute position properties to screen position. The resulting point is correct for the Windows platform but unfortunately in Android platform the point is not accurate.
Procedure TForm50.Cube1Render(Sender: TObject; Context: TContext3D);
var p:TPoint3D;
x,y:real;
Begin
p:=context.worldtoscreen(TProjection.Camera, Cube1.AbsolutePosition);
Label1.Text:=(p.x.tostring+' '+P.Y.ToString);
x:=p.X-(CalloutPanel1.Width /2);
y:=p.y-CalloutPanel1.Height;
CalloutPanel1.Position.X:=x;
CalloutPanel1.Position.y:=y;
End;
update
Base of this post WorldToScreen function C# my Cube1.AbsolutePosition must change base on size of monitor(android screen) to place CalloutPanel1 over cube1.
Who can apply this code on Delphi?

Low quality delphi user interface design under Android when using TImage

Since Android phones are released in many different screen resolutions and my user interface is "skinned" using multiple TImage components, I've hit a major development issue, I must scale each of my images relative to the device's screen resolution.
For some reason which I can not understand, under Android, TImage is interpolated using a really low quality scaler (possibly nearest-neighbor), resulting in a very low quality image display (this happens even when the screen scale is taken into consideration and the form's quality is set the high).
Due to this, it means I can either pre-scale and include multiple different resolutions of the same image, hoping that it will look 'close enough' (and bloating my app), or I can use a software algorithm to scale the images in real-time and then cache the result for later runs.
I choose the second option, using a software bicubic scaler, but the problem is that my app has so many image resources, it can take 18 seconds to load the first time on a high end mobile device.
I'm aware it may be possible to do what I need in hardware using OpenGL, but I haven't been able to find a clear/clean example of how this can be done in Delphi for Android. And even if it can be done without having to re-code the entire UI for OpenGL.
Is there something I'm missing design wise?
Is a fix from Embarcadero my only chance?
It took me a while to lock this down, but here is Android native code that will scale the image in high quality much faster than any pure software solution I could find and optimize:
uses Androidapi.JNI.Media, Androidapi.JNI.GraphicsContentViewText, Androidapi.JNIBridge, FMX.Surfaces, FMX.Helpers.Android;
procedure AndroidResizeBitmap(srcBitmap,dstBitmap : TBitmap);
var
sJBitmap : JBitmap;
ScaledBitmap : JBitmap;
sSurface : TBitmapSurface;
begin
sSurface := TBitmapSurface.Create;
sSurface.Assign(srcBitmap);
sJBitmap := TJBitmap.JavaClass.createBitmap(sSurface.Width, sSurface.Height,TJBitmap_Config.JavaClass.ARGB_8888);
SurfaceToJBitmap(sSurface, sJBitmap);
ScaledBitmap := TJBitmap.JavaClass.createScaledBitmap(sJBitmap, dstBitmap.Width, dstBitmap.Height, True);
sJBitmap := nil;
JBitmapToSurface(ScaledBitmap,sSurface);
ScaledBitmap := nil;
dstBitmap.Assign(sSurface);
sSurface.Free;
sSurface := nil;
end;

DELPHI XE8 : No refresh for TRectangle on Android during OnCreate event

I created this function on DELPHI XE5, it's work very well.
You create a single image with all your icons, you load this image in a TBitmap (IDE in my exemple), and you create a lot of small TRECTANGLE in the form.
During the onCreate, i call Mapping method to set the background of each Trectangle.
BUT IN DELPHI XE8, It's not working on ANDROID
This is the mapping function.
Procedure TForm1.Mapping(Const Obj:TRectangle;Const ofx,ofy:Integer);
Var
Arect : TRectF;
FBitmap : TBitmap;
Begin
Arect:=TRectF.Create(0,0,Obj.Width,Obj.Height);
Obj.Stroke.Kind := TBrushKind.None;
Obj.Fill.Kind := TBrushKind.Bitmap;
Obj.Fill.Bitmap.WrapMode := TWrapMode.TileOriginal;
//Create Crop Bitmap
FBitmap:=TBitmap.create( Round(Obj.Width), Round(Obj.Height)) ;
Try
FBitmap.Canvas.BeginScene();
FBitmap.Canvas.ClearRect(ARect,StringToAlphaColor('$00000000'));
FBitmap.Canvas.DrawBitmap(IDE,
TRectF.Create(ofx,ofy,ofx+Obj.Width,ofy+Obj.Height),
Arect, 100) ;
FBitmap.Canvas.EndScene;
//Assign Crop image to Rectangle object
Obj.Fill.Bitmap.Bitmap.Assign(FBitmap);
Finally
FBitmap.Free;
End;
End;
The picture (delphiXE.png) is deploying in "asset/internal", and opening in oncreate.
procedure TForm1.FormCreate(Sender: TObject);
Var Mfile:String;
begin
IDE := TBitmap.Create(ClientWidth,ClientHeight);
{$IFDEF ANDROID}
Mfile:=TPath.Combine(TPath.GetDocumentsPath, 'delphiXE.png');
{$ELSE}
Mfile:=TPath.Combine(ExtractFilePath(ParamStr(0)), 'delphiXE.png');
{$ENDIF}
If FileExists(MFile)
Then begin
IDE.LoadFromFile(MFile);
Mapping(Logo,0,0);
End
Else ShowMessage('NO '+MFile);
end;
In Windows, everythings works fine, but no in Android, but if i add a simple onclick event with Mapping(Logo,0,0); call, the mapping work, but i need to click first on the grey Trectangle to set it background
Any idea ?
UPDATED :
Using a Timer, the mapping function is working and the trectangle have the good picture, but if i switch to another application and go back to my application, the picture disappear and the Trectangle turn back to solid gray.
That mean that the internal paint of the TRectangle is not updated. Why ?
Thanks for you help, i find a solution and the origin of the problem.
The fact that the picture in the Trectangle was not persistent help me.
//Assign Crop image to Rectangle objects
Obj.Fill.Bitmap.Bitmap.Assign(FBitmap);
is no longer working like it worked on DELPHI XE5 on Android. It 's copy the bitmap but not on a persistent way. This is why it's working with onclick, but disappear when i switch application.
So, I changed this line by
// Force the size of TRectangle internal Bitmap
Obj.Fill.Bitmap.Bitmap.SetSize(FBitmap.Width,FBitmap.Height);
// Copy the crop bitmap in TRectangle Internal Bitmap
Obj.Fill.Bitmap.Bitmap.CopyFromBitmap(FBitmap);
and in my TEST PROJECT, it's working.
I hope this can help another developper.
Did you try to test the return of Canvas.BeginScene ? If it's fail, that mean that the graphic context system does not succeded to init. (yes, that work on XE5 and perhaps other, go figure, they perhaps change the init sequence somewhere)
In Creation phase, certainly not abnormal.
you should do this somewhere else.

Strange Delphi Android image assign / image garbled issue

I have some code that works fine in iOs, but which results in completely messed up images when on Android. I have found a partial workaround (not call some code), but it hints something is terrible wrong:
// some bitmap object buffer for mainthread only
R.BitmapRef := FPersistentBitmapBuffer;
// this TImage now contains the original wrongly sized bitmap
ImageBackground.Bitmap.Assign(R.BitmapRef);
// calculated somewhere
TmpNewWidth := 500;
TmpNewHeight := 500;
// draw the bitmap resized to wanted size
R.BitmapRef.Width := Round(TmpNewWidth);
R.BitmapRef.Height := Round(TmpNewHeight);
R.BitmapRef.Canvas.BeginScene();
R.BitmapRef.Canvas.DrawBitmap(ImageBackground.Bitmap, RectF(0,0,ImageBackground.Bitmap.Width,ImageBackground.Bitmap.Height), RectF(0,0,TmpNewWidth,TmpNewHeight), 1);
R.BitmapRef.Canvas.EndScene();
// assign it back to the image
ImageBackground.Bitmap.Assign(R.BitmapRef);
// THIS code causes the image shown in TImageBackground to look completely garbled ... which would indicate something is shareing memory/reference somewhere somehow... There is more odd behavior like debugger unhooking (it seems) if mouse in Delphi debugger hovers over ImageBackground.Bitmap - no error is reported
R.BitmapRef.Clear(TAlphaColorRec.White);
As can be seen, it the last line that messes it up. In some tests it has seemed to be enough to remove he line, but not in others. This is my best lead/description/example of the problem.
Here is an example of how a garbled image looks like. Since they look garbled the same way each time I run the app, I suspect it must be somehow relate to the image, but there is not any visual similarity.
My question is what could be wrong? I am testing the Delphi XE7 trial, so I can not access the source. It worked flawlessly on iOS using XE4 and XE7, but with Android something is going on. I am thinking it could possibly be some bitmap data that is sharing a reference... Does anyone have any ideas on how to test this theory / possible workarounds?
This looks plainly wrong. I'd suggest that you fill a bugreport at http://quality.embarcadero.com
Try using CopyFromBitmap instead of the "Assign". This will create a unique copy of the image. You'll also get a new unique image if you call MyBitmap.Map(TMapAccess.Write, MyBitmapData); followed by MyBitmap.UnMap(MyBitmapData);.

Categories

Resources