Welcome Guest! You need to login or register to make posts.

Notification

Icon
Error

Options
Go to last post Go to first unread
jaouellette  
#1 Posted : Monday, May 10, 2004 2:07:00 AM(UTC)
jaouellette

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
Code:
objBitmap.DrawOnBitmap

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

Andrew  
#2 Posted : Monday, May 10, 2004 2:52:00 PM(UTC)
Andrew

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

jaouellette  
#3 Posted : Monday, May 10, 2004 9:26:00 PM(UTC)
jaouellette

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

;)
Andrew  
#4 Posted : Monday, May 10, 2004 10:28:00 PM(UTC)
Andrew

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:
  1. Do transparentize with small tolerance.
  2. Extract alpha channel (with objBitmap.Channels.Extract(3)). You will get 8-bit grayscale image.
  3. Apply blur, median filter or maybe contrast enchancement on alpha.
  4. 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

jaouellette  
#5 Posted : Tuesday, May 11, 2004 3:41:00 AM(UTC)
jaouellette

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

Andrew  
#6 Posted : Tuesday, May 11, 2004 1:40:00 PM(UTC)
Andrew

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

jaouellette  
#7 Posted : Tuesday, May 11, 2004 8:59:00 PM(UTC)
jaouellette

Rank: Member

Groups: Member
Joined: 4/30/2004(UTC)
Posts: 16

Andrew,

I emailed the 2008.jpg (The portrait)

UserPostedImage

and the newEEWhite.jpg (The background)

UserPostedImage

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):
GraphicsMill_581_FrontImage.jpg
GraphicsMill_581_BackgroundImage.jpg
jaouellette  
#8 Posted : Tuesday, May 11, 2004 9:09:00 PM(UTC)
jaouellette

Rank: Member

Groups: Member
Joined: 4/30/2004(UTC)
Posts: 16

Here is an example of the result that I get:

UserPostedImage

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):
GraphicsMill_581_BadResult.jpg
Andrew  
#9 Posted : Tuesday, May 11, 2004 9:46:00 PM(UTC)
Andrew

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:

UserPostedImage

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):
GraphicsMill_581_GoodResult.jpg
jaouellette  
#10 Posted : Tuesday, May 11, 2004 10:15:00 PM(UTC)
jaouellette

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
Andrew  
#11 Posted : Wednesday, May 12, 2004 12:12:00 PM(UTC)
Andrew

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.
Andrew  
#12 Posted : Wednesday, May 12, 2004 8:53:00 PM(UTC)
Andrew

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:

UserPostedImage

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):
GraphicsMill_581_BestResult.jpg
jaouellette  
#13 Posted : Wednesday, May 26, 2004 5:43:00 AM(UTC)
jaouellette

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
Andrew  
#14 Posted : Wednesday, May 26, 2004 4:21:00 PM(UTC)
Andrew

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

jaouellette  
#15 Posted : Wednesday, May 26, 2004 10:41:00 PM(UTC)
jaouellette

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...
Andrew  
#16 Posted : Wednesday, May 26, 2004 11:55:00 PM(UTC)
Andrew

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

Users browsing this topic
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.