Aurigma Forums
»
Legacy Products
»
Archive
»
Other Products
»
Transparent portrait on a background image
Rank: Member
Groups: Member
Joined: 4/30/2004(UTC) Posts: 16
|
I would like to display a portrait of 300 x 375 pixels on a background image of 3165 x 5055 pixels. The portrait has a background color of White and I would like to make the White transpanrent and the background image to show through this color. Could you provide me with and example of how to execute this. I have tried using the Code:objBitmap.Channels.Transparetize
method as well as the method and I can not seem to get it to work. Thank you, Jason... Edited by user Monday, December 24, 2007 5:30:00 PM(UTC)
| Reason: Not specified
|
|
|
|
Rank: Advanced Member
Groups: Member, Administration Joined: 8/2/2003(UTC) Posts: 876
Thanks: 2 times Was thanked: 27 time(s) in 27 post(s)
|
This code sample demonstrates how to use both methods: Code:<!-- METADATA TYPE="typelib" UUID="{3CE48541-DE7A-4909-9314-9D0ED0D1CA5A}"-->
<%
Dim objPortrait, objBackground
Set objPortrait = Server.CreateObject("GraphicsMill.Bitmap")
Set objBackground = Server.CreateObject("GraphicsMill.Bitmap")
objPortrait.LoadFromFile Server.MapPath("portrait.jpg")
objBackground.LoadFromFile Server.MapPath("background.jpg")
objPortrait.Data.ConvertTo32bppArgb
' Second parameter is a tolerance. It specifies how close pixel should be to the target pixel.
' If tolerance = 0, only pixels which are exactly equal to the target one are transparentized.
' If tolerance is >0, algorithm also transparentizes pixels which are close to target color.
' It allows to avoid aliasing on the edges of your portrait.
objPortrait.Channels.Transparentize ColorWhite, 5
Dim x, y
x = 100
y = 300
objPortrait.DrawOnBitmap objBackground, x, y, , , , , , , CombineModeAlpha
objBackground.SaveToStream Response
objBackground.SaveToFile Server.MapPath("Result.jpg")
%>
Use x and y variables to specify position of the image. If you omit them, the image will be drawn at (0,0) point (top left corner). Draw attention, I have attached Graphics Mill type library to this page to be able to use constants like ColorWhite or CombineModeAlpha. If you do not like add reference to type library you can use &hFFFFFFFF instead of ColorWhite and 1 instead of CombineModeAlpha. Please let me know if anything is unclear. Edited by user Monday, December 24, 2007 5:30:13 PM(UTC)
| Reason: Not specified
|
|
|
|
Rank: Member
Groups: Member
Joined: 4/30/2004(UTC) Posts: 16
|
Andrew, Thank you for the example. I have now got the portrait displaying on the background in the proper location. I do have one more issue that I am hoping you can help me with. The portrait has a White background and I have specified the ColorWhite constant with a tolerance between 0 and 20. Using a tolerance level of over 20 starts to make the teeth transparent, so I am using 20 as my tolerance level. The problem is that although I can see the background through the transparent color, it has almost a ghost quality so that I can see the rectangle around the portrait still defined rather then a smooth blend of the colors. Is there a way to blend the two images together better? Thanks, Jason P.S. I am using VB6 ;)
|
|
|
|
Rank: Advanced Member
Groups: Member, Administration Joined: 8/2/2003(UTC) Posts: 876
Thanks: 2 times Was thanked: 27 time(s) in 27 post(s)
|
Well... As far as understand, the background color of the portrait image is not pure white (it is compressed with JPEG or so)? In this case you can try the following approach: - Do transparentize with small tolerance.
- Extract alpha channel (with objBitmap.Channels.Extract(3)). You will get 8-bit grayscale image.
- Apply blur, median filter or maybe contrast enchancement on alpha.
- Retrieve this image back to the portrait.
For example with blur you will have slight white halo around the object, but it will be looking much better than "ragged" edges. Here is a code sample (it is on VBScript, because I modified another code sample written for ASP, but I think it is easy to reuse it in VB6... sorry): Code:<!-- METADATA TYPE="typelib" UUID="{3CE48541-DE7A-4909-9314-9D0ED0D1CA5A}"-->
<%
'Declarations
Dim objBackground ' The background image. It will contain the result of merge.
Dim objBitmap ' The image you put on the background.
Dim objMask ' This bitmap will contain alpha channel
Dim strBackgroundFilename
Dim strBitmapFilename
Dim strMergedFilename
' Specify file names here
strBitmapFilename = Server.MapPath("FrontImage.jpg")
strBackgroundFilename = Server.MapPath("BackgroundImage.jpg")
strMergedFilename = Server.MapPath("Result.jpg")
' Create bitmaps
Set objBitmap = Server.CreateObject("GraphicsMill.Bitmap")
Set objBackground = Server.CreateObject("GraphicsMill.Bitmap")
' Load bitmaps
objBackground.LoadFromFile strBackgroundFilename
objBitmap.LoadFromFile strBitmapFilename
objBitmap.Data.ConvertTo32bppArgb
objBitmap.Channels.Transparentize ColorWhite, 2
Set objMask = objBitmap.Channels.Extract(3)
'objMask.ColorAdjustment.Contrast 50
'objMask.Effects.MaximumFilter 2
'objMask.Effects.MedianFilter 1
objMask.Effects.Blur 1
objBitmap.Channels.Replace objMask, 3
' Apply alpha blending
objBitmap.DrawOnBitmap objBackground, , , , , , , , , CombineModeAlpha
' Save the result
objBackground.SaveToFile strMergedFilename
objBackground.SaveToStream Response
' Cleanup
Set objMask = Nothing
Set objBitmap = Nothing
Set objBackground = Nothing
%>
I hope this will help. Edited by user Friday, May 23, 2008 4:05:34 PM(UTC)
| Reason: Not specified
|
|
|
|
Rank: Member
Groups: Member
Joined: 4/30/2004(UTC) Posts: 16
|
Andrew, Again thank you for you quick response! I have implemented the changes that you recommended, but it only made the issue worst not better. The transparent area is more of a ghost quality rather than transparent. Do you have any other idea's that I could try? Thank you, Jason... Here is the sample code I am working with: Code: Dim ObjHt, ObjWt As Long
Dim objBitmap As New Bitmap
Dim objBitmapPort As New Bitmap
Dim objBitmapMask As New Bitmap
Set objBitmapPort = Nothing
Set objBitmap = Nothing
Set objBitmapMask = Nothing
objBitmap.LoadFromFile "c:\newEEWhite.jpg"
objBitmapPort.LoadFromFile "C:\2008.JPG"
objBitmapPort.Data.ConvertTo32bppArgb
objBitmap.Data.ConvertTo32bppArgb
objBitmapPort.Channels.Transparentize ColorWhite, 20
Set objBitmapMask = objBitmapPort.Channels.Extract(3)
objBitmapMask.Effects.Blur 1
objBitmapPort.Channels.Replace objBitmapMask, 3
locx = ScaleX(260, vbPixels, vbPoints)
locy = ScaleY(550, vbPixels, vbPoints)
portwt = ScaleX(300, vbPixels, vbPoints)
portht = ScaleY(375, vbPixels, vbPoints)
objBitmapPort.DrawOnBitmap objBitmap, locx, locy, portwt, portht, , , , , CombineModeAlpha, 255, InterpolationModeHighQuality
objBitmap.HorizontalResolution = 300
objBitmap.VerticalResolution = 300
objBitmap.Unit = UnitPoint
ObjWt = ScaleX(54, vbMillimeters, vbPoints)
ObjHt = ScaleY(85.6, vbMillimeters, vbPoints)
objBitmap.Transforms.Resize ObjWt, ObjHt, InterpolationModeHighQuality
objBitmap.Data.ConvertToCmyk True
For Each prnPrinter In Printers
If prnPrinter.DeviceName = "Pro-L Card Printer" Then
Set Printer = prnPrinter
bFound = True
Exit For
End If
Next
Printer.Duplex = 1
Printer.PrintQuality = -4
objBitmap.Unit = UnitPoint
Printer.ScaleMode = vbPoints
Printer.CurrentX = 0
Printer.CurrentY = 0
Printer.Print ""
objBitmap.DrawOnHDC Printer.hDC
Printer.EndDoc
Me.Picture = objBitmap.Data.Picture
Set objBitmap = Nothing
Set objBitmapMask = Nothing
Set objBitmapPort = Nothing
Edited by user Monday, December 24, 2007 5:51:32 PM(UTC)
| Reason: Not specified
|
|
|
|
Rank: Advanced Member
Groups: Member, Administration Joined: 8/2/2003(UTC) Posts: 876
Thanks: 2 times Was thanked: 27 time(s) in 27 post(s)
|
Could you submit case with an example of portrait image and example of result you want to get, and I will say you if it is feasible with the current version of Graphics Mill (without customization). Edited by user Friday, May 23, 2008 4:06:00 PM(UTC)
| Reason: Not specified
|
|
|
|
Rank: Member
Groups: Member
Joined: 4/30/2004(UTC) Posts: 16
|
Andrew, I emailed the 2008.jpg (The portrait) 
and the newEEWhite.jpg (The background) 
These are the images that I am working with and I sent them to [email removed]. Thank you! Jason... Edited by user Monday, December 21, 2009 3:22:29 AM(UTC)
| Reason: Not specified jaouellette attached the following image(s):
|
|
|
|
Rank: Member
Groups: Member
Joined: 4/30/2004(UTC) Posts: 16
|
Here is an example of the result that I get: 
As you can see the square box is still very visible. Thanks, Jason... Edited by user Monday, December 21, 2009 3:22:53 AM(UTC)
| Reason: Not specified jaouellette attached the following image(s):
|
|
|
|
Rank: Advanced Member
Groups: Member, Administration Joined: 8/2/2003(UTC) Posts: 876
Thanks: 2 times Was thanked: 27 time(s) in 27 post(s)
|
The problem is that the portrait image is quite damaged with JPEG artifacts (it seems it has been recompressed to JPEG several times and with low quality). That's why the background of the JPEG is not totally white - it is very uneven. That's why Transparentize does not make some sections of background totally transparent. To reduce this problem you can increase the contrast of alpha channel, for example with this line: Code:objMask.ColorAdjustment.Contrast 75
However you won't get rid of another problem: "square" halo around the woman's head: 
You can make it looking slightly better (for example by blurring it), but you cannot remove it at all (at least automatically). To avoid these problems you should use portrait images of higher quality. Ideally it should not be in JPEG format, but if JPEG files are obligatory to you, it should be of good enough quality (it should not be visually divided into small squares). Edited by user Monday, December 21, 2009 3:23:22 AM(UTC)
| Reason: Not specified Andrew attached the following image(s):
|
|
|
|
Rank: Member
Groups: Member
Joined: 4/30/2004(UTC) Posts: 16
|
Andrew, The contrast setting works very well and is more than good enough quality! You support has been outstanding and my company will be issuing a Purchase order for the Graphics Mill 2.0 Single Developer License today! Thank you again for all your help and I look forward to working with you and the Graphics Mill products! Jason... :D
|
|
|
|
Rank: Advanced Member
Groups: Member, Administration Joined: 8/2/2003(UTC) Posts: 876
Thanks: 2 times Was thanked: 27 time(s) in 27 post(s)
|
Jason, Glad to know that it resolved your problem. Please feel free to let me know if you experience any other problem with Graphics Mill.
|
|
|
|
Rank: Advanced Member
Groups: Member, Administration Joined: 8/2/2003(UTC) Posts: 876
Thanks: 2 times Was thanked: 27 time(s) in 27 post(s)
|
By the way, I played with alpha channels some more and managed to get better result. I used these operations: Code:' Playing with brightness to remove unnecessary tone levels.
objMask.Brightness -254
objMask.Brightness 126
'Increase contrast to maximum
objMask.ColorAdjustment.Contrast 100
'It makes edges more smooth and fixes transparent teeth.
objMask.Effects.MedianFilter 3
Here is a result image: 
The only problem I see here is a slightly broken hair, but it almost removes a halo around the head though. I hope it helps. P.S. Note, median filter works quite slow, so I would still recommend avoid using it until it is necessary indeed (especially if portrait images will be large). Edited by user Monday, December 21, 2009 3:23:54 AM(UTC)
| Reason: Not specified Andrew attached the following image(s):
|
|
|
|
Rank: Member
Groups: Member
Joined: 4/30/2004(UTC) Posts: 16
|
What is the easiest way using this example to auto detect the background color of the portrait and make that color the color used for transparency rather than requiring users to provide a color? This way it they have some images with a blue background and some with a white background, the same code would work for both. Also can a background color like White be detected and then replaced with a user defined color like Red? So I detect the back ground color of the portrait and then want to change what ever that color is to Red. Thanks, Jason... :D
|
|
|
|
Rank: Advanced Member
Groups: Member, Administration Joined: 8/2/2003(UTC) Posts: 876
Thanks: 2 times Was thanked: 27 time(s) in 27 post(s)
|
> What is the easiest way using this example to auto detect the background color of the portrait and make that color the color used for transparency rather than requiring users to provide a color? This way it they have some images with a blue background and some with a white background, the same code would work for both. If you are sure that, say, target object is always in the center of image, you can assume that the most top and left pixel is a background. In this case you can take it in the following way: Code:Dim backgroundColor
backgroundColor = objBitmap.Data.Pixels(0,0)
' Use this background in Transparentize...
To reduce "error of second kind" (probability to select wrong background color), you can take several neighbor pixels and compare them (if these colors are equal or close enough, it is likely background). Anyway, you should leave user possibility to change selected background in case if algorithm will mistake. But I guess it will greatly reduce number of user interventions. >Also can a background color like White be detected and then replaced with a user defined color like Red? So I detect the back ground color of the portrait and then want to change what ever that color is to Red. The simplest way I can suggest is to: - Take a background color (either manually or automatically), e.g. White
- Apply transparentize.
- Generate new image filled with necessary color, e.g. Red (see reference for CreateNew method of Bitmap object for more details).
- Alpha-blend our image on this empty image.
Hopefully it will help. Edited by user Monday, December 24, 2007 5:31:31 PM(UTC)
| Reason: Not specified
|
|
|
|
Rank: Member
Groups: Member
Joined: 4/30/2004(UTC) Posts: 16
|
> To reduce "error of second kind" (probability to select wrong background color), you can take several neighbor pixels and compare them (if these colors are equal or close enough, it is likely background). Once I get the sample pixels that I think are the background, how do I calculate the average of the colors select assuming that I will sample six pixels (3 from the top left, and 3 from the top right) Thanks, Jason...
|
|
|
|
Rank: Advanced Member
Groups: Member, Administration Joined: 8/2/2003(UTC) Posts: 876
Thanks: 2 times Was thanked: 27 time(s) in 27 post(s)
|
First of all, before you average these pixels you should make sure that they does not have noticeable difference (otherwise it is unlikely background pixels). To do it, just find per-channel difference between each pair of pixels and if it is higher than some tolerance value (say 5), and if you find at least one discrepancy, it means you should search for background color in some other way (take other pixels). To average colors, you should perform per-channel addition and divide them on the number of pixels. To make it more clear, I will put a small code snippet below: Code:' For brevity we will use Color class included into Graphics Mill
' Faster way would be to handle numeric values (decompose Long value
' containing RGB triad into Bytes containing individual channels), but for 6 pixels
' we won't get noticeable effect.
Dim pixels(6) As color
' ...
' Let's assume you filled this array with appropriate pixels
' and ensured that you can treat them as background.
' Now we compose new Color value.
' Declare components as Long values.
' We do not use Byte to avoid overflow, but
' final value will contain number in range [0, 255]
Dim lngRed As Long
Dim lngGreen As Long
Dim lngBlue As Long
' Do not forget to initialize these values!
lngRed = 0
lngGreen = 0
lngBlue = 0
' Calculate per-channel sum
Dim I As Long
For I = LBound(pixels) To UBound(pixels)
lngRed = lngRed + pixels(I).GetRed
lngGreen = lngGreen + pixels(I).GetGreen
lngBlue = lngBlue + pixels(I).GetBlue
Next I
' Find number of elements of array to divide
Dim count As Long
count = UBound(pixels) - LBound(pixels) + 1
' objAverage - object which will construct the numeric value
' (stored in lngAverage)
Dim objAverage As New Color
Dim lngAverage As Long
lngAverage = objAverage.CreateRgb (lngRed/count, lngGreen/count, lngBlue/count)
' Use lngAverage as a background in next operations.
I hope this helps. Edited by user Monday, December 24, 2007 5:31:38 PM(UTC)
| Reason: Not specified
|
|
|
|
Aurigma Forums
»
Legacy Products
»
Archive
»
Other Products
»
Transparent portrait on a background image
Forum Jump
You cannot post new topics in this forum.
You cannot reply to topics in this forum.
You cannot delete your posts in this forum.
You cannot edit your posts in this forum.
You cannot create polls in this forum.
You cannot vote in polls in this forum.