OpenCV - end cap control - android

I am attempting to draw a line (with line()) with square endings, but can not find any documentation telling me how to do it. So far all my lines end in little triangles.
Can this be done? Is its something to do with lineType?
EDIT: An example of my usage...
line(ptr_to_mat, Point(10,25), Point(30,25), Scalar(255,0,0,0),4, 8, 0);
EDIT: I should have mentioned, this is running on an Android device.

According to OpenCV docs, function line() will draw thick lines with rounding endings.
That said, you cannot directly get over this. But, you can draw it several times with thickness=1 or draw a filled rectangle instead to achieve your goal (both ugly though :():
line(ptr_to_mat, Point(10,23), Point(30,23), CV_RGB(255,0,0), 1, 8, 0);
line(ptr_to_mat, Point(10,24), Point(30,24), CV_RGB(255,0,0), 1, 8, 0);
line(ptr_to_mat, Point(10,25), Point(30,25), CV_RGB(255,0,0), 1, 8, 0);
line(ptr_to_mat, Point(10,26), Point(30,26), CV_RGB(255,0,0), 1, 8, 0);
You will get:

Also from the Docs - "The line is clipped by the image boundaries." - maybe you can clip the round edges out of the line by drawing the line inside of a Mat's Region Of Interest (ROI, a.k.a. submat). Basically you have to set the dimensions of the ROI with the size of the line minus the round tips. If this sound too complex, it is simpler than that.
It is not very elegant but considering that the clipping is done for free within the line drawing algorithm this probably more efficient than drawing several lines / rectangles.
Another thing, try to change the lineType parameter, it might change the tip rendering.
lineType:
8 (or omitted) - 8-connected line.
4 - 4-connected line.
CV_AA - antialiased line.
Or you can always implement your own line renderer?
I never said it would be pretty :D

the topic is a bit old but I faced this problem recently and I found a solution by using the library wxpython. Maybe it could help, here is a code example:
import wx
app = wx.App()
frame = wx.Frame(None, title="Draw on Image")
imgBit = wx.Bitmap(width=512, height=512, depth=1)
dc = wx.MemoryDC(imgBit)
pen = wx.Pen(wx.RED, 3)
pen.SetCap(wx.CAP_BUTT)
dc.SetPen(pen)
dc.DrawLines(((32, 32), (64, 32)))
dc.SelectObject(wx.NullBitmap)
imgBit.SaveFile("bitmap.png", wx.BITMAP_TYPE_PNG)
Hope it will help someone in the future

Related

Compare two objects in image

I need to compare two images to find the equality . I have searched a lot about AR and openCV. Already gone through compare two images in android and Tried OpenCV samples too . With OPENCV only ORB is free to use and it will compare images in GrayScale and thats not what i need.
P.S:- The need is i have 4 images of a object in my app. SO if user scan a real object using camera then i need to figure out the object in this scanned image does match any of the object in those 4 images or not. I know it way off-topic and also too broad as per SO standard but I really need help on this.
EDIT:- After trying some algos from github i stumble upon on This project . And the results are quite satisfying . I already have tested it with several templates . I am stuck here with one problem . I need to show to user whether the object found or not(a boolean) . How can i determine this if object is detected correctly or not ?
Putting some final step code below.
Point point1=new Point(sceneCorners.get(0,0));
Point point2=new Point(sceneCorners.get(1,0));
Point point3=new Point(sceneCorners.get(2,0));
Point point4=new Point(sceneCorners.get(3,0));
Imgproc.line(rgb, point1, point2, new Scalar(0, 255, 0), 4);
Imgproc.line(rgb, point2, point3, new Scalar(0, 255, 0), 4);
Imgproc.line(rgb, point3, point4, new Scalar(0, 255, 0), 4);
Imgproc.line(rgb, point4,point1, new Scalar(0, 255, 0), 4);
the 2 points are found on each detection . How can i determine that it detected the object or not ? Some things i already tried :
1. Check for rectangle formed with those points:- This can fail .
What is the recommended approach for solving this problem. I have searched a lot most of every sample on github but not found a solution for this .
Please let me know which approach should i follow ?

How to work with anti-alias on delphi firemonkey and 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

How to use OpenCV to process image so that the text become sharp and clear?

Wanted to achieve something like this: http://www.leptonica.com/binarization.html
While searching for solutions, most of the answers were general instructions such as advise to look at adaptive filter, gaussian blur, dilation and erosion but none of them provide any sample code to start with (so can play around with the values)..
I know different image require different methods and values to achieve optimum clarity, but I just need some general filter so that the image at least slightly sharper and less noisy compare to the original, before doing any OCR on it.
this is what I've tried so far..
Mat imageMat = new Mat();
Utils.bitmapToMat(photo, imageMat);
Imgproc.cvtColor(imageMat, imageMat, Imgproc.COLOR_BGR2GRAY);
Imgproc.GaussianBlur(imageMat, imageMat, new Size(3, 3), 0);
Imgproc.adaptiveThreshold(imageMat, imageMat, 255, Imgproc.ADAPTIVE_THRESH_MEAN_C, Imgproc.THRESH_BINARY_INV, 5, 4);
but being an image processing newb, obviously I don't know what I'm doing XD
original image:
after applying the above:
How to do it correctly?
UPDATE: got it much closer thanks to metsburg, berak and Aurelius
Using the medianBlur method since cvSmooth with CV_MEDIAN is deprecated and replaced with medianBlur:
Imgproc.medianBlur(imageMat, imageMat, 3);
Imgproc.threshold(imageMat, imageMat, 0, 255, Imgproc.THRESH_OTSU);
Result:
Using back the GaussianBlur method, the result actually is slightly better:
Imgproc.GaussianBlur(imageMat, imageMat, new Size(3, 3), 0);
Imgproc.threshold(imageMat, imageMat, 0, 255, Imgproc.THRESH_OTSU);
Result:
For this image the difference is not noticable, so I tried another image which is a photo taken off the computer screen. Computer screen gives a lot of noises (wavy lines) so it is very hard to remove the noise.
Example original image:
Directly applying otsu:
using medianBlur before otsu:
using GaussianBlur before otsu:
Seems like gaussian blur is slightly better, however I'm still playing with the settings..
If anyone can advise on how to improve the computer screen photo further, please, let us know :)
One more thing.. using this method on the image inside the top link yields horrible results :( see it here: http://imgur.com/vOZAaE0
Well, you're almost there. Just try these modifications:
Instead of
Imgproc.GaussianBlur(imageMat, imageMat, new Size(3, 3), 0);
try:
cvSmooth(imageMat, imageMat, CV_MEDIAN, new Size(3, 3), 0);
check the syntax, may not exactly match
The link you posted uses thresholding of Otsu, so try this:
Imgproc.threshold(imageMat, imageMat, 0, 255, Imgproc.THRESH_OTSU);
for thresholding.
Try tweaking the parameters here and there, you should get something pretty close to your desired outcome.
Instead of using Imgproc.THRESH_BINARY_INV use Imgproc.THRESH_BINARY only as _INV is inverting your image after binarisations and resulted is the said output shown above in your example.
correct code:
Imgproc.adaptiveThreshold(imageMat, imageMat, 255, Imgproc.ADAPTIVE_THRESH_MEAN_C, Imgproc.THRESH_BINARY, 5, 4);

Chart drawing fine on emulator but not on phone

I drew a basic Smith chart on the canvas using circles, arcs and lines. I have run the app on numerous size emulator screens and all work perfectly but once I tried it on an actual device (Android level 2.3.5) the chart does not line up as it should i.e. some objects are out of place.
While writing the code I was careful to use get.Width() and get.Height() for the parameters instead of using pixels so that the app would work correctly on all devices. Below is an example of the code i used:
canvas.drawCircle(canvas.getWidth()*1/2, canvas.getHeight()*3/8, canvas.getWidth()*475/1000, black);
canvas.drawCircle(canvas.getWidth()*5/8, canvas.getWidth()*5/8, canvas.getWidth()*349/1000, black);
canvas.drawCircle(canvas.getWidth()*6/8, canvas.getWidth()*5/8, canvas.getWidth()*228/1000, black);
canvas.drawCircle(canvas.getWidth()*7/8, canvas.getWidth()*5/8, canvas.getWidth()*103/1000, black);
arc0.set(canvas.getWidth()/2, canvas.getHeight()*-139/700, canvas.getWidth()*100/69, canvas.getHeight()*3/8);
arc1.set(canvas.getWidth()*-6/112, canvas.getHeight()*-80/100, canvas.getWidth()*195/100, canvas.getHeight()*72/192);
arc2.set(canvas.getWidth()*7/10, canvas.getHeight()*70/700, canvas.getWidth()*125/100, canvas.getHeight()*3/8);
arc3.set(canvas.getWidth()/2, canvas.getHeight()*3/8, canvas.getWidth()*100/69, canvas.getHeight()*91/96);
arc4.set(canvas.getWidth()*-8/112, canvas.getHeight()*3/8, canvas.getWidth()*195/100, canvas.getHeight()*150/100);
arc5.set(canvas.getWidth()*7/10, canvas.getHeight()*3/8, canvas.getWidth()*125/100, canvas.getHeight()*65/100);
The graph lines up fine on all the different size emulator screens i have tried, so would anybody be able to tell me why it doesn't line up on an actual device. Thanks
You have to use percentage values not numbers... moreover try to take a look on conversions of the value u r getting from getwidth(). Possibly some values are missing..

How to change brightness of an image in android?

I am developing an Image manipulation software in android.i want to change the brightness of an particular image.how it can be done in code?
I'm using something like this at the moment:
if (brighter)
{
darknessPaint.setColorFilter(new PorterDuffColorFilter(Color.argb(level, 255, 255, 255), Mode.SRC_OVER));
}
else
{
darknessPaint.setColorFilter(new PorterDuffColorFilter(Color.argb(level, 0, 0, 0), Mode.SRC_ATOP));
}
darknessCanvas.setBitmap(dst);
darknessCanvas.drawBitmap(src, 0, 0, darknessPaint);
Indeed you could use LightningColorFilter too or ColorMatrixColorFilter. If anyone has a better (and by that I mean faster, besides using JNI which I haven't tried yet) method please let me know.
You probably want to look at LightingColorFilter and Drawable, or if you want to perform the manipulation manually, look at Bitmap - specifically getPixels and setPixels (or copyPixelsFromBuffer and copyPixelsToBuffer if you wish).

Categories

Resources