A METHOD FOR THE AUTOMATIC COMPUTERIZED AUDIO VISUAL DUBBING OF MOVIES

Abstract: A method using computer software for automatic audio visual dubbing (5), using an efficient computerized automatic method for audio visual dubbing of movies by computerized image copying of the characteristic features of the lip movements of the dubber onto the mouth area of the original speaker. The invention uses a method of vicinity-searching, three-dimensional head modeling of the original speaker (3), and texture mapping (10) technique to produce new images which correspond to the dubbed sound track. The invention thus overcomes the well known disadvantage of the correlation problems between lip movement in an original movie and the sound track of the dubbed movie.

Description: A METHOD FOR THE AUTOMATIC COMPUTERIZED AUDIO VISUAL DUBBING OF MOVIES FIELD OF THE INVENTION The present invention relates to a method for automatic audio visual dubbing. More specifically the said invention relates to an efficient computerized automatic method for audio visual dubbing of movies by computerized image copying of the characteristic features of the lips movements of the dubber onto the mouth area of the original speaker. The present invention uses a method of vicinity-searching, three-dimensional head modeling of the original speaker, and texture mapping techniques in order to produce the new images which correspond to the dubbed sound track. The invention overcomes the well known disadvantage of the correlation problems between lips movement in the original movie and the sound track of the dubbed movie. DEFINITIONS OF TERMS RELATED TO THE INVENTION First are provided some definitions of important key words employed in this specification. Actor (the original actor) - an actor, speaker, singer, animated character, animal, an object in a movie, or a subject in a still photograph. Audio Visual Dubbing - Manipulating, in one or more frames, the mouth area of the actor so that its status will be similar as much as possible to that of the dubber in the reference frame. Correlation Function - A function describing the similarity of two image regions. The higher the correlation, the better is the match. Dubber - The person or persons, who speak/narrate/sing/interpret the target text. The dubber can be the same as the actor. Dubbing - Replacing part or all of one or more of the original sound tracks of a movie, with its original text or sounds (including the case of the silent track of a still photograph), by another sound track containing the target text and/or sound. Edge Detector - A known image processing technique used to extract boundaries between image regions which differ in intensity and/or color. Face Parametrization - A method that numerically describes the structure, location, and expression of the face. Head Model - A three-dimensional wire frame model of the face that is controlled by numerous parameters that describe the exact expression produced by the model (i.e. smile, mouth width, jaw opening, etc.). Movie (the original movie) - Any motion picture (e.g. cinematic feature film, advertisement, video, animated cartoon, still video picture, etc.). A sequence of consecutive pictures (also called frames) photographed in succession by a camera or created by an animator. In the case of the movie being a still photograph, all of the consecutive pictures are identical to each other. When shown in rapid succession an illusion of natural motion is obtained, except for the case of still pictures. A sound-track is associated with most movies, which contains speech, music, and/or sounds, and which is synchronized with the pictures, and in particular where the speech is synchronized with the lip movements of the actors in the pictures. Movies are realized in several techniques. Common methods are: (a) recording on film, (b) recording in analog electronic form ("video"), (c) recording in digital electronic form, (d) recording on chips, magnetic tape, magnetic disks, or optical disks, and (e) read/write by magnetic and/or optical laser devices. Finally, in our context, an "original movie" is also an audio-visual movie altered by the present invention, which serves as a base for further alterations. Original Text - A text spoken or sung by the actor when the movie is being made, and which is recorded on its sound track. The text may be narrated in the background without showing the speaker, or by showing a still photograph of the speaker. Pixel - Picture element. A digital picture is composed of an array of points, called pixels. Each pixel encodes the numerical values of the intensity and of the color at the corresponding picture point. Reference Similarity Frame - A picture (being a frame in the original movie, a frame in any other movie, or a still photograph) in which the original actor has the desired features of the mouth-shape and head posture suitable for the audio visually dubbed movie. Target Text - A new vocal text, to replace the original vocal text of the actor. The target text may also be that which is to be assigned to an actor who was silent in the original movie. The new text can be in another language, to which one refers as DUBBING. However, this invention relates also to replacement of text without changing the language, with the original actor or with a dubber in that same language. The target text may have the same meaning as the original text, but may have also a modified, opposite, or completely different meaning. According to one of many applications of the present invention, the latter is employed for creation of new movies with the same actor, without his/her/its active participation. Also included iε new vocal text used to replace the null vocal text attached to one or more still photographs. Texture Mapping - A well known technique in computer graphics which maps texture onto a three-dimensional wire frame model. Two-Dimensional Projection - The result of the rendering of the three-dimensional face model onto a two- dimensional device like a monitor, a screen, or photographic film. BACKGROUND OF THE INVENTION Movies are often played to an audience that is not familiar with the original language, and thus cannot understand the sound track of such movies. Two well known common approaches exist to solve this problem. In one approach sub-titles in typed text of the deεried language are added to the pictures, and the viewers are expected to hear the text in a foreign language and simultaneously to read its translation on the picture itself. Such reading distracts the viewers from the pictures and from the movie in general. Another approach is dubbing, where the original sound-track with the original text iε being replaced by another sound-track with the desired language. In this case there is a disturbing mis-match between the sound-track and the movements of the mouth. There have been some earlier attempts to overcome these disadvantages, none of which have been commercialized because of inherent principal difficulties which made the practical execution unrealistic. Thus, in U.S. Patent Number 4,600,281 a method is described which performs the measurements of the shape of the mouth manually by a ruler or with a cursor, and corrects the mouth shape by moving pixels within each frame. As will be seen in the description of the invention, the method according to the present invention iε inherently different and much superior in the following points: In the present invention the tracking of the shape of the mouth is done automatically and not manually. In the present invention changing the shape of the mouth is done by using a three- dimensional head model, for example like those described by P.Ekman and W.V.Friesen, (Manual for the Facial Action Unit System, Consulting Psychologist Press, Palo Alto 1977). In the present invention the mouth area of the 97/15926 actor is replaced using the mouth area of a reference similarity frame. In the present invention mouth status parameters of the dubber are substituted for mouth status parameters of the actor. The U.S. Patent Number 4,260,229 relates to a method of graphically creating lip images. This U.S. patent is totally different from the present invention: In the U.S. Patent, speech sounds are analyzed and digitally encoded. In the present invention no sound analysis is done; nor is any required at all. To make for better viewing of the audio visually dubbed movie, the present invention provides a computerized method wherein, in addition to replacing the sound track to the target text, the mouth movements of the actor are being automatically changed to match the target text. The new mouth movements are linguistly accurate and visually natural looking according to all of the observable parameters of the actor's face. SUMMARY OF THE INVENTION The present invention provides a method for automated computerized audio visual dubbing of movies, comprising of the following steps (see Fig. 1): /15926 (a) selecting from the movie a frame having a picture, preferably frontal, of the actor's head and, if available, a frame with its side profile; (b) marking on the face several significant feature points and measuring their locations in the frame; (c) fitting a generic three-dimensional head model to the actor's two-dimensional head picture by adapting the data of the significant feature points, as measured in stage (b), to their location in the model; (d) tracking of the said fitted three-dimensional head model parameters throughout the movie, from one frame to its successor, iteratively in an automated computerized way and creating a library of reference similarity rames. (e) taking a movie of a dubber wherein the dubber speaks the target text; (f) repeating stages (a), (b) , (c), and (d) with the dubber; (g) normalizing the dubber's minimum and maximum values of each parameter to the actor's minimum and maximum valuse of the same parameters; (h) mapping, on a frame to frame basis, the two- dimensional actors face onto its three-dimensional head model by using a texture mapping technique, making use of reference similarity frames; (i) changing the texture mapped three-dimensional model obtained in stage (h) by replacing, on a frame to frame basis, the original mouth parameters with the mouth parameters as computed in stage (d) for the dubber and obtaining the parametric description for the new picture, with identical values to the original, except that the actor's mouth status resembles the mouth status of the dubber; (j) texture mapping the lips area of the same actor from a frame in the movie, with identical or very similar mouth status to the desired new mouth status, onto the lips area of the actor's head model for the current frame and then projecting the lips area from the actor's head model onto the current new frame. (This stage is optional, depending on the application. ) By using the three dimensional head model one can control the audio visual dubbing procesε even if the actor iε moving his head. In most applicationε about 15 significant feature points on the face are used in the tracking stage, such as eye corners, mouth cornerε, and the nostrills. Only those feature points which are visible to the viewer (using the information available to the model) are tracked. In the present invention, audio visual dubbing is normally used in conjunction with the use of audio dubbing; but one may also use it in conjunction with an audio track where no equivalent track exists in the original movie. The method according to the present invention iε useful for the audio visual dubbing of motion pictures such as cinematic feature films, advertisments, video, and animated cartoon. Also the audio visual dubbing of still photographs, wherein all of the frames of the movie are the same, is made poεεible by the present invention. For instance, still photographs are used for this type of movie in T.V. news programs where the reporter's voice iε heard while a still photograph of him/her is shown. Thus, according to the present invention even speachless actors, infants, animals, and inanimate objects can be audio visually dubbed to speak in any language. According to our invention, the animation process saves much of the labor associated with the animation of the 97/15926 11 mouth area. The present invention further provides a computer program (see Appendix 1) for operating the computerized audio visual dubbing. The present invention further relates to the library of reference similarity frames as created in step d (above). DETAILED DESCRIPTION OF THE INVENTION Given an original movie where an actor speaks the original text, a movie of a dubber is made where the dubber speaks the target text in either another language or the same language. The movie of the dubber is taken while the dubber performs a routine dubbing adaptation of the original into the target text. Thiε invention provides a method for the changing of the actor'ε facial motionε in the original movie to create a new movie having the sound-track in the target text from the movie of the dubber, while the pictures are of the original movie, whereas the motion of the mouth of the actor is modified to correspond to the new sound-track. For brevity considerations, the description of thiε invention uses pictures in electronic digital form (composed of an array of pixels) , but movies in any other form are treatable as well. In these cases, the movie is translated to a digital form by existing techniques, manipulated in the digital form, and returned back to any desired form by known techniques. A facial expression can be described by an "action unit", for example the Facial Action Coding System (FACS) by Ekman and Friesen (Ekman et. al.). Action units (AU) standε for a small change in the facial expression which depends on a conscious activation of muscles (H. Li, P. Roivainen, R. Forchheimer, 3-D Motion in Model-Based Facial Image Coding, IEEE Transactions in PAMI, 15 (2), 545—555 (1993)). The AU information is expressed in parameter form. Using the AU parameters, many facial expressions can be controlled. Parameters like face location and size, aspect-ratios of face regions, location of specific face fetures and many more. Aε explained above, one of the stages of this invention is a three-dimensional parameterisation of the face. An example for one such model iε the model of Parke (Fredric I. Parke, Parameterized Models for Fatial Animation, IEEE computer Graphics and Applicationε, 12 (11), 61-68, (1982)) which consists of about 25 parameters. Face parameters can be roughly divided into three main classes: structure parameterε, location ,, ,„„ PCT/IB96/01056 97/15926 13 parameters, and expression parameters. Structure parameters are fixed for every head and include distance ratios between the mouth and the eyes, the mouth and the chin, width of the model, jaw width, etc. The location parameters are, for example: three parameters for three-dimensional rotation in space and three parameters for three-dimensional translation (position in the real world). The expression parameterε are, for instance: mouth width, smile (aε an example, the parameter values here may be 0.0 for a very sad mouth and 1.0 for a very happy mouth), jaw opening, upper lip lifting, lower lip lowering, lip thickness, and so on. Using a face model, the present invention is centered on a computer program (see Appendix 1), which automaticly re-shapes the lip movements of the actor according to the lip movements of the dubber by εearching for the nearest reference similarity frames. Thiε computer program (software), or similar, is an integral and an important part of the present invention. The procesε, according to the present invention, is divided generally into the TRACKING phase and the NEW-MOVIE generation phase, as follows: I. TRACKING phase Step l: The first step is personalizing the generic three-dimensional face model for both the actor and the dubber. In order to modify the generic face model to fit a specific face, some additional information is needed. The generic model has to be translated, scaled and stretched to fit the given actor's face, from its initial position and setting. This is done by manually pointing using a pointing device such as a mouth, a touch screen, etc. , several facial feature points on the actor•ε ace, e.g. eye cornerε, mouth cornerε, top and bottom of face. Typically a total of approximately 15 feature pointε are used, but thiε number may vary according to specifications. These feature pointε are marked on one (any) of the frames in the movie, in which the actor, preferably, faces the camera. The computer program then calculates automatically the exact model parameter's modifications needed for its two-dimensional projection to fit the actor face on the movie frame. In addition to using the facial feature points and in order to increase accuracy, the model is also adjusted to match the head edges, which are computed using an edge detector. If a side view of the actor is available it can be used to set several depth parameterε, such aε face depth and nose length. Otherwise, the face depth is scaled by some predetermined scale which iε set experimentally. Step 2: After the generic face model has been personalized to the desired actor, face features in several key frames in the movie are marked. The number of such frames can vary from a single first frame to about 5% of all frames, depending on the difficulty of the segment fitting the model to the actor using the marked facial features in those key frameε achieves a stabilization of the automatic tracking (described later), and these key frames assures stable and continuous tracking. Next, the program calibrates according to several examples of mouth shapes, later to be used for mouth tracking. Finally, the range of the mouth parameterε (mimimum and maximum values) for the specific actor are estimated using all the values of the model parameters fitted to all key frames. Step 3: The next stage is the automatic tracking of the actor's face throughout the entire movie: Thiε is performed from one frame to its successive frame, using the face model, in two steps: first, the two-dimensional face of the actor iε mapped onto the three-dimenεional face model using a texture-mapping technique. The model can now be altered by changing its parameterε only, creating new, synthetic images, which are otherwise very similar to the original movie frames: everything remains unchanged except for different face location, its orientation, and its expressions. By using a minimization algorithm, either analytic or numerical (such as steepest descent algorithm) , the program now computes those parameters which maximize the correlation function between the face area of the actor in the next frame and the synthesized projection of the texture-mapped face model. The steepest descent algorithm increases or decreases parameters in the direction that increases the correlation function. It can either work for each parameter separately (until it maximizes the correlation), or it can modify all the parameters at once. Step 4: After the model is locked on the head of the actor in the next frame, the mouth has to be tracked. This is done by first, checking the parameters of all of the mouths in the key frames and in several previous frames already tracked. Then, the frame that gives the higher correlation iε choosen as a first guess for the tracking. Next, the same minimization algorithm used to track the global head motion is used, until the correlation function has maximized. The parameters describing the face model in the tracked frame are written into a file for later use. Step 5: Steps 3 and 4 are repeated until the entire movie iε processed. For best results, instead of executing this process serially from the first frame to the last, the key frameε can be used aε initial pointε of tracking. Every two consecutive key frames are used to track from each of them to the frameε between them. That way, stabilasation of the tracking is preserved. Step 6: The tracking described above is applied to the dubber movie as well. II . NEW MOVIE generation phase Thiε phase combines the tracking results of both the original and the dubber's movies, in order to synthesize the new audio visually dubbed movie. This audio visually dubbed movie, as explained above, is mostly formed out of the original movie, except for the face of the actor in thiε audio visually dubbed movie. This face is a texture- mapped face on the three-dimensional face model, synthesized, as described above, to fit the lip, mouth, and cheek shapeε of the dubber at that particular time. Thus, the parameterε of the face model computed aε described in phase I, is used to produce the new audio visually dubbed movie, in which for every frame in the original movie, the mouth parameters are modified to those of the dubber. The exact process is as follows: Step 7: For every frame in the original movie, the face of the actor iε texture-mapped on the appropriate face model using the parameters that were calculated in step 3 for the original movie. The mouth parameterε of the dubber as calculated in step 3 are used as follows for the new audio visually dubbed movie. Step 8: Once the desired mouth-shape of the actor is known, the original movie iε being searched in the neighborhood of the current frame (approximately 0.1 - 10 seconds forwards and backwards in time) for a mouth that is most similar in shape or parameters to the new desired mouth. Thiε search for the reference similarity frame takes into account the mouth-shape already chosen for the previous frame in order to make the mouth motion smooth and continuous. From the several (5 - 10) best fit mouths, the mouth which is picked is from the frame that iε closest in time to the previouε picked mouth. Step 9: The mouth chosen in step 8 is texture-mapped into the mouth model using its pre-computed parameters. The face model parameters are then changed to the desired mouth shape, producing a very realistic new frame, which replaces the old frame in the original movie. The user of the program can choose the deεired mouth area to be texture-mapped in place - it can be either the inside of the mouth, the whole mouth including the lips or even a bigger area. This procedure creates a synthesized image, in which the face around the mouth, and in particular the lips, are re-shaped according to the sound track, while retaining the familiar face of the original actor. Step 8 can also be skipped, so that the inside of the mouth will be empty. This is useful for making a talking movie from still picture, where the inside information of the mouth iε missing; because in the reference frame similarity dictionary of the actor there does not exist any near fit of lip shapes for the target. This black interior can also be filled with visual color/texture. Step 10: Finally, the sound track from the dubbed movie (target text) replaces the original text and sound. It iε to be noted that an animator using the invented software tool, is free to modify, set, or fix any of the head or mouth parameters, in both the original or audio visually dubbed movie, and even pick a specific mouth to be textured-mapped in place, as described in step NM8, all of these at any of the above stages. The tracking program is highly interactive and user-friendly. The involved software (see Appendix 1) of thiε invention is very versatile, and can be used in a very wide array of sound/text replacement applications many of which have been mentioned above. The following are exa pleε of εome applications of the present invention: Advertising: For products sold world-wide, an original advertising commercial can be manipulated to produce the same commercial in any desired language. Thiε saves the need to produce a new video for every country or language that the product is aimed for. Another possibility is to edit a movie, by altering existing scenes without having to re-shoot them again. If, for example, after the movie production was over, the director/editor wishes to alter a specific scene, or change one sentence of a specific actor. The present invention refers not only to narrated text but also to songs, operas, and music, opening the possibility to change the language of musical video clips. The production of an animated cartoon is assisted by drawing a line segment for the actor's mouth, drawing a small actor's picture dictionary containing representive reference similarity frameε with completely drawn mouths, and then allowing these lip-line segments to be replaced with the coresponding lip shapes of the dubber as are to be found in the actor's picture dictionary. In general, applications of a method for automatic audio visual dubbing of movie include: cinematic movies, cartoons, documentarie , advertizing, news, educational programs, court documentations, speaches, lectures. historical documentation, hearing committees, home videos, sports events, entertainment events, operas, musicals, musical video-clips, simultaneous translation, and adding speach to sequences of either original or added still frames of the aforesaid. Furthermore, using the library of the previously described reference similarity frames, the present invention allows one to create new movies altogether, and also to convert background narrative to audio visual speach, and to audio-visualize any written text. The present invention will be further described by Figures 1-4. These figures are solely intended to illustrate the prefered embodyment of the invention and are not intended to limit the scope of the invention in any manner. Likewise the attached software (Appendix 1) represents an example of the implementation of the method disclosed in the present patent and is not intended to limit the scope of said method in any way. Figure l illustrates a block diagram showing the method stages, and its contents is is detailed below. Figures 2a and 2b illustrate an example of significant points on a generic frontal picture of a head (Figure 2a) and a generic side profile picture of a head (Figure 2b). Figure 3 shows an example of a generic wire frame face model. For illustrative purposes one can take the significant points shown in Figures 2, measure them on pictures of a real actor, and apply them to a generic wire frame face model (Figure 3). Fitting a three-dimensional head model to the actor's two-dimensional head picture by adapting the data of the significant pointε, aε measured, results in an integration, as can be seen in Figures 4a and 4b. Figure 4a is an example showing how a custom fitted wire frame model fits onto a frontal view of an actor's face. Figure 4b is an example showing how a custom fitted wire frame model fitε onto a profile view of an actor's face. Figure 1 illustrates a block diagram showing the method stages: In the original movie (l) a frame is selected (2) having a nearly frontal picture of the original actor's head and, if available, a frame is alεo selected having a picture with hiε side profile. A three-dimensional head model is fitted to the actor's two dimensional head picture(s). This model can be controlled by several parameterε such aε for the position of the head and the status of the mouth. This fitting stage (3) is done by adapting the data of the significant points, as measured in the selected frame, to the model. The next step (4) iε the automated computerized tracking of the fitted three-dimensional head model parameterε throughout the movie, from one frame to the next. One partial or complete three-dimensional head model for each frame where the actor appears, iε used. Any of the resulting frameε can serve as a reference similarity frame for the lips replacement. A movie of the dubber is taken (5). In thiε movie the dubber aceε the camera in moεt of the frames. The dubber speakε the target text in thiε movie. The same process aε applied to the original actor'ε movie iε applied to the dubber'ε movie: A frame form the dubber's movie is selected (6) having a frontal picture of the dubber'ε head, and if available, a frame with a picture of his side profile. A three dimensional head model iε fitted to the dubber'ε two dimenεional head picture (7) by adapting the data of the εignificant pointε, aε measured in the selected frame, to the dubber's model. An automated computerized tracking (8) of the said dubber*s fitted three dimensional head model parameters is taken throughout the movie, from one frame to the next. The next stage in this method is to normalize (9) the dubber'ε minimum and maximum parameters to the actor's minimum and maximum parameters. In a frame to frame fashion, the original actor'ε two dimensional face iε mapped (10) onto hiε three dimensional head model. Thiε mapping stage is done by using a texture mapping technique with the reference similarity frames. The result of this stage is one mapped three dimensional partial head model of the original actor for each frame of the original actor in the original movie; wherein the model, corresponding to a given frame may be complete in the case when the original frame contains a frontal view of the actor's face. In the next stage the textured three dimensional model frames obtained for the original actor are changed (11) by replacing, on a frame to frame basis, the original mouth parameters with mouth parameters as computed for the dubber in the corresponding frames; correspondance being determined by the desired sound track substitution (i.e. the dubbing). Thus iε obtained the parametric description for a new picture identical to the original, except that the actor's mouth status resembles the mouth status of the dubber; wherein the new picture coresponds to a frame in the new audio visually dubbed movie. In order to overcome difficulties like for example those that arise when the dubber in (6) opens a closed mouth in (4), a frame or frames in the original movie are sought whose mouth status is similar to the desired new mouth status. These frames, termed reference similarity frames, are usually but not necessarily in a temporal proximity to the processed frame, and the lips from that frame are copied using texture mapping (12) into the lips area in the new frame. The search for a reference similarity frame is an essential component of the present invention. We therefore repeat itε definition: a reference similarity frame is a picture (being a frame in the original movie, a frame in any other movie, or a still photograph) in which the original actor haε the desired features of the mouth-shape and head posture suitable for the audio visually dubbed movie. Alternatively, the reference similarity frame may be taken from a compiled picture library of the original actor or of other actors. The process (12) iε repeated all over again for each frame, until the entire movie is converted. FACE IMAGING Ltd source code for program 'dub The following printout includes the source for the following modules: dub.c main program general .c general functions and utilities gimg.h interface for gi g.c - image I/O and filtering mv.h interface for mv.c - moving handling list.h interface for list.c - list data type handling io.c I/O functions texture.c texture mapping stuff These modules comprises the program 'dub' which automatically fixes the lips of a person in a movie to another person's lip shapes, as described in the invention description. The modules included are the main modules. Utility modules, such as handling images, movies, etc. are not included. SUBSTITUTESHEET(RULE28) * Module: dub.c * By: Ranco * History: * 18.8.94: creation. ft****************************************** #mclude <event.h> #ιnclude "x inc.h" #ιnclude "defs.h" #mclude "image.h" #mclude "general.h" #mclude "mv.h" #ιnclude "vars.h" #mclude "dub.h" #ιnclude "gimg.h" #mclude "lo.h" #ιnclude "texture h" #ιnclude <math.h> #ιnclude <dmedιa/cl_cosmo.h> #ιnclude <audιofιle.h> Movie movιe,out_movιel, out_movιe2,trans_movιe, XtAppContext ac; Widget tl, da; Display *dpy, GC gc; char output_movιe_name[MAX NAME], source_movιe_name[MAX_NAME], trans_movιe_name[MAX_NAME],dubbed_movιe_name[MAX_NAME], force_frames_filename[MAX_NAME],full_dubbed_movie_name[MAX_NAME], audio file name [MAX N AME] , mt first frame, last_frame, translator first rame; mt sample = l,frame_range = FRAME AREA, jpeg quahty; float mouth scale; int avg_params_flag = FALSE, avg width flag = TRUE, force frames flag = FALSE, int full_flag = FALSE; Parameter **left_source_array, **πght_source_array; Parameter **left_trans_array, **right_trans_array; extern int texture map; Gimg curr frame 1; int one frame mode, normalize mouth, verbose mode; i n t w h ι c h _ p a r a m s [ ] = {JAW_ROTAΗON,MTH_YSC1,RSE_UPLIP,LWRLIP_SHIN,UPLIP_SHIN,LWRLIP_FTUCK ,MTH_INTERP}; int ranges[] = {1,2,1,1,1,0,1}; AFfilehandle audio 1 = AF NULL FILEHANDLE, audio2 = AF NULL FILEHANDLE; int play flag; /* * GLX configuration parameter: * Double buffering * color index (default so unspecified) * nothing else special */ static GLXconfig glxConfig [] = { { GLX_NORMAL, GLX_DOUBLE, FALSE }, { GLX_NORMAL, GLX_ZSIZE, 7 }, { GLX NORMAL, GLX_RGB, TRUE }, { 0, 0, 0 } /* texture properties for the whole face */ float texpropsl[] = { TX MINFILTER, TX_POINT, TXJVlAGFILTER, TX_POINT, TX_WRAP, TX_CLAMP, TX_NULL}; /* texture properties for the lips */ float texprops2[] = { TX_MINFILTER, TX_BILINEAR, TX_MAGFILTER, TX_BILINEAR, TX_WRAP, TX_C AMP, TX_NULL}; /* Texture environment for the face and the lips */ float tevpropsl [] = {TV DECAL, TV NULL}; /******.ι.********»**********-ι..<.^ void Refresh(mt dl, int d2) { if (RedrawNeeded) { recompute_face(); DrawScene(); RedrawNeeded = FALSE; void cancelCB(Widget w, XtPointer xtp, GlxDrawCallbackStruct "call data) { exιt(0); } void da_mitCB( Widget w, XtPointer xtp, GlxDrawCallbackStruct *call_data) { zbuffer(TRUE); wmconstraintsO, reshapeviewportO; subριxel(TRUE), mmode(MVIEWING); ortho(-xsιze/2.0+.5,xsιze/2.0+.5,-ysιze/2.0+.5,ysιze/2.0+.5,-500.0,2000.0); zfar = getgdesc(GD ZMAX), lsetdepth(0, zfar); zclear(); cpack(bgc), clear(); concave(FALSE); mmode(MPROJECTION), getmatπx(mp); mmode(MVIEWING), frontbuffer(TRUE); RedrawNeeded = TRUE; } void da_resetCB(Wιdget w, XtPointer xtp, GlxDrawCallbackStruct *call_data) { RedrawNeeded = TRUE; void UIInιt(mt *argc, char **argv) { Widget cancel, form, rc,rcl, go, sep, label; XColor color, uu; Colormap cmap; Pixel bg_color, top shadow, bottom shadow, fg, select color; XmStπng frame_str = XmStπngCreateSιmple( "Frame: "), label str = XmStπngCreateSιmple(" D E M O "), wf str = XmStnngCreateSιmple(" 1/1 "), go str = XmStnngCreateSιmple(" Go!"), cancel str = XmStπngCreateSιmple("Quιt"), tl = XtAppInitiahze (&ac, "Dub", NULL, 0, argc, argv, NULL, NULL, 0), dpy = XtDisplay (tl); form = XtVaCreateManagedWidgetf'form", xmFormWidgetClass, tl, XmNnoResize, TRUE, NULL); da = XtVaCreateManagedWidget ("da", glxMDrawWidgetClass, form, GlxNglxConfig, glxConfig, XmNwidth, xsize, XmNheight, ysize, XmNbottomAttachment, XmATTACH FORM, XmNtopOffset, 2, XmNbottomOffset, 2, XmNbackground, WHITE, NULL), XtAddCallback(da, GlxNresizeCallback, (XtCallbackProc)da resetCB, NULL), XtAddCallback(da, GlxNexposeCallback, (XtCallbackProc)da_resetCB, NULL), XtAddCallback(da, GlxNginitCallback, (XtCallbackProc)da_mιtCB, NULL), XtReahzeWidget (tl), } /•*****«*** _>***************************^ void Inιt(ιnt argc, char **argv) { char vbuff[50], long zbuf = getgdesc(GD_BITS_NORM_ZBUFFER), long rgb_sbιts[3], rgb_dbιts[3], mt l, ch, source movie name flag = 0, trans movie name flag = 0,last_frame_flag=0, int n_frames,prm, char model_fιlename[MAX_NAME], char temp[MAX_NAME], params[MAX_NAME], xsize = getgdesc(GD_XPMAX), if (argc < 5) ProgUsage(argv[0]), gversιon( vbuff ), rgb_sbιts[0] = getgdesc(GD_BITS_NORM_SNG_RED), rgb_sbιts[l] = getgdesc(GD_BITS_NORM_SNG_GREEN), rgb_sbιts[2] = getgdesc(GD_BITS_NORM_SNG_BLUE), rgb_dbιts[0] = getgdesc(GD_BITS_NORM_DBL_RED), rgb_dbιts[l] = getgdesc(GD_BITS_NORM_DBL_GREEN), rgb_dbιts[2] = getgdesc(GD_BITS_NORM_DBL_BLUE), ok_for_shadmg= ( (rgb_sbιts[0]>0) && (rgb_sbιts[l]>0) && (rgb_sbιts[2]>0)), ok_for_double_buffeπng= ( (rgb_dbιts[0]>=OK_FOR_DOUBLE_BUFFERING) && (rgb_dbιts[ 1 ]>=OK_FOR_DOUBLE_BUFFERING) && (rgb_dbιts[2]>=OK_FOR_DOUBLE_BUFFERING)), ιf(debug) { fpπntf(stdout, "Machine is %s at res %ld\n",vbuff,xsιze), fpπntf(stdout,"zbuffer bits is %ld\n",zbuf), fpπntf(stdout,"rgb single is %ld,%ld,%ld\n",rgb_sbιts[0],rgb_sbιts[l],rgb_sbιts[2]), fpnntf(stdout,"rgb double is %ld,%ld,%ld\n",rgb_dbιts[0],rgb_dbιts[l],rgb_dbιts[2]), } /* initialize some globals */ prefix = "DATA/face_model", texture map = FALSE, param face = TRUE, eye_posιtιon_not_set = TRUE, show model = TRUE, hps only = FALSE, put image = TRUE, which image = FRONT IMG, show teeth = FALSE, show coord = TRUE, wire = TRUE, one frame mode = FALSE, mouth area = TEX NONE, normalize mouth = TRUE, verbose mode = FALSE, current wmdow = MAIN, curr saved unage = 1, RedrawNeeded = RecalcNeeded = TRUE; mouth scale = 1.0; first_frame = translator_first_frame = DEF_FIRST_FRAME; strcpy(output_movιe_name, DEF_OUTPUT_MOVIE_NAME); params[0] = 0; jpeg quahty = 93; play_flag = FALSE; bgc = 0x00202020; ι = 1; tex mode = DUB MODE; whιle(~argc && (ch = argv[ι++][l])) { switch (ch) { case 's'- /* Source movie */ strcpy(source_movιe_name, argv[ι++]); source_movιe_name_flag++, break; case 'o'. /* New movie */ strcpy(output_movιe_name, argv[ι++]); break; case 't': strcpy(trans_movιe_name, argv[ι++]); trans mo vi e_name_flag++ ; break; case 'u' strcpy(force_frames_filename, argv[ι++]); force frames_flag++ ; break; case : first frame = atoι(argv[ι++]); break; case T: last frame = atoι(argv[ι++]); last_frame_flag++; break; case 'q': jpeg quality = atoi(argv[i++]); sprintf(temp,"-qL%d",jpeg_quality); strcat(params,temp); break; case 'm': if (stmcmp(argv[i-l],"-mc",strlen("-mc")) == 0) { sscanf(argv[i++],"%lx",&bgc); printf( "Mouth color = %x\n",bgc); } else { mouth scale = atof(argv[i++]); sprintf(temp,"-rn_%.2f',mouth_scale); strcat(params,temp) ; } break; case 'F': translator first frame = atoi(argv[i++]); break; case V: frame range = atoi(argv[i++]); sprintf(temp,"-r_%d",frame_range); strcat(ρarams,temp); break; case 'w': strcat(params,"-w"); wire = TRUE; put image = FALSE; argc++; break; case 'a': if (argv[i-l][2] == 'p') avg_params_flag = TRUE; else if (argv[i-l][2] == 'w') avg width flag = TRUE; strcat(params,argv[i- 1 ]); argc++; break; case 'b': full_flag = TRUE; argc++; break; case 'n': normalize_mouth = FALSE; argc++; break; case T: /* use INside of mouth */ if (argv[i-l][2] = 'N') mouth_area = TEX_IN; strcat(params,"-IN"); argc++; break; case 'E': /* use EXTERNAL mouth */ if (!strncmp(argv[i-l]+2, "XT",2)) mouth_area = TEX_EXT; strcat(params,"-EXT"); argc++; break; case 'O': /* use OUTside of mouth */ if (argv[i-l][2] == 'U') mouth_area = TEX_OUT; strcat(params,"-OUT"); argc++; break; case V: verbose mode = TRUE; argc++; break; default: fprintf(stdeιτ, "%c is an illegal flag!\n", (char)ch); argc++; break; } argc--; } .source movie name flag || Itrans movie name) ProgUsage(argv[0]); make_face(), /* read data, topology and parameters */ if (Iput image) { fgc=0xFF000000, /* set background color */ bgc=OxFFFFFFFF, /* set foreground color. */ } object_ιs_vιsιble[FLESH] = TRUE, object_ιs_vιsιble[LIPS] = TRUE; object_ιs_vιsιble[EYELASH] = TRUE, objecι_ιs_vιsιble[TEETH] = FALSE; object is visiblefPUPIL] = FALSE, object is visibleflRIS] = FALSE; object_ιs_vιsιble[FRINGE] = FALSE; object_ιs_vιsιble[EYEWHITE] = FALSE, setPolarAzιmuth(O.O) , setPolarInc(90.0), setPolarTwιst(O.O), saved front sc = saved_sιde_sc = sc; spπntf(model_filename,"%s.model",source_movιe_name), restoreModel(model filename), spπntf(temp, "%s %d prm", source movie name, first frame), PRINTFl("Restoπng params from %s\n", temp); restoreParameters(temp,left__parameter,rιght_parameter.FALSE), mth color = 01, /* Create output movies and open input movies */ if ((movie = MOVIE_open(source_movιe_name)) — NULL) { exιt(0); > xsize = MOVIE frameWιdth(movιe); ysize = MOVIE_frameHeιght(movιe); pπntfC'Source frame size is (%dx%d)\n",xsιze,ysιze), if ((trans movie = MOVIE_open(trans_movιe_name)) == NULL) { exιt(O), } spπntf(audιo_file_name,"%s a",trans_movιe_name); if (full_flag) { spπntf(full_dubbed_movιe_name,"%s%s_FULLSIZE",output_movιe_name,params), pnntfT'Creating movie %s.mv\n",full_dubbed_movιe_name), out moviel = MOVIE_create(full_dubbed_movιe_name,xsιze,ysιze, MOVIE frameRate(trans movie), MOVIE_audιoRate(trans_movιe), DM_TOP_TO_BOTTOM, DM_IMAGE_JPEG, DM_IMAGE_INTERLACED_EVEN, jpeg_quahty), audiol = MOVIE_createAudιoTrack(audιo_file name,out_movιel); > else { spπnt (dubbed_movιe_name,"%s%s",output_movιe_name,params), pnntf("Creating movie. %s.mv\n",dubbed_movιe_name); out_movιe2 = MOVIE_create(dubbed_movιe_name,xsιze/2,ysιze/2, MOVIE_frameRate(trans_movιe), MOVIE audιoRate(trans movιe), DM_BOTTOM_TO_TOP, DM_IMAGE_MVC1, DM MAGE NONINTERLACED, jpeg quahty), audιo2 = MOVIE_createAudιoTrack(audιo_file_name,out_movιe2), } if ('last frame flag) last frame = MOVIE_numOfFrames(movιe)-l; if (MOVIE numOfFrames(movιe) == 1) one fra e mode = TRUE, curr framel = GimgCreate (xsιze,ysιze,GRGBA); n frames = last frame + 1 , MALLOC(left_source_array,n_frames,Parameter_ptτ), MALLOC(πght_source_array,n_frames,Parameter_ptr); restoreAllParameters(source_movie_name,n_frames, left_source_array,right_source_array); MALLOC(left_trans_array,n_frames,Parameter_ptr); MALLOC(right_trans_array,n_frames,Parameter_ptr); restoreAHParameters(trans_movie_name,n_frames, left_trans_array,right_trans_arτay); if (verbose mode) { for (i=0; i < XtNumber(which_params); i++) { prm = which_params[i]; printf( "%s\t", left_parameter[prm] .box label) ; } float calcParamDist (int frame no) < float distance=0, min dist = SOME BIG NUMBER, t[5], range; Parameter *p_ll, *p_12, *p_rl , *p_r2; int k; p ll = left source arrayfframe no]; p rl = right_source_array[frame_no]; p_12 = left_parameter; p_r2 = right_parameter; range = MAX_VAL(p_ll[JAW_ROTATION])-MIN_VAL(p_ll[JAW_ROTATION]); t[0] = (VAL(p_ll [JAW_ROTATION])-VAL(p_12[JAW_ROTATION]))/range; range = MAX_VAL(p_ll[MTH_Yscl])-MIN_VAL(p_ll[MTH_Yscl]); t[l] = (VAL(pJl[MTH_Yscl])-VAL(p_12[MTH_Yscl]))/range; t[2] = (VAL(p_rl[MTH_Yscl])-VAL(p_r2[MTH_Yscl]))/range; range = MAX_VAL(p_ll[RSE_UPLIP])-MIN_VAL(p_ll[RSE_UPLIP]); t[3] = (VAL(p_ll[RSE_UPLIP])-VAL(p_12tRSE_UPLIP]))/range; range = MAX_VAL(p_ll[LWRLIP_FTUCK])-MIN_VAL(p_ll[LWRLIP_FTUCK]), t[4] = (VAL(p_ll [LWRLIP_FTUCK])-VAL(p_12[LWRLIP_FTUCK]))/range, for (k=0, k<5, k++) distance += fabs(t[k]), return (distance), int dist comp (const void *dl, const void *d2) { float diff = ((dist st *)dl)->dιstance - ((dist st *)d2)->dιstance, if (diff < 0 0) return -1 , else if (diff > 0 0) return 1 , return 0, } / ***************************************^ int angleTooFar (int a) { Parameter *ls = left source arrayfa], *lp = left_parameter, float twist 1 = VAL(ls[POLAR_TWIST]), twιst2 = VAL(lp[POLAR_TWIST]), if (twistl >= 180 0) twistl -= 360 0, if (twιst2 >= 180 0) twιst2 -= 360 0, if ((fabs(VAL(ls[POLAR_AZIM])-VAL(lp[POLAR_AZIM])) > 10 0) || (fabs(VAL(ls[POLAR_INC])-VAL(lp[POLAR_INC])) > 10 0) || (fabs(twιstl-twιst2) > 10 0)) { return (TRUE), } return (FALSE), } **************************«***************^ int scaleTooFar (int a) { Parameter *ls = left source arrayfa], *lp = left_parameter; float ratio = VAL(ls[SCALE])/VAL(lp[SCALE]); if (ratio < 0.9 || ratio > 1.1) return (TRUE), return (FALSE), mt loadMouth (int firame no, int last chosen) { mt l, j, k, best fit = SOME_BIG_NUMBER, width,heιght,mdex = SOME BIG_NUMBER, closest, d, found 1, bigger mouth; int from = MAX(fϊrst_frame,frame_no-frame_range), to = MIN(last_frame,_τame_no+frame_range); float distance, mm_dιst = SOME BIG NUMBER; char temp[MAX_NAME]; Gimg sub img; dist st *dιstances; for (ι=from; I < to; ι++) { distance = calcParamDιst(ι); distance /= fsιn(RAD(1.5*(_-last_chosen)+90.0)); if (dιstance-mιn_dιst<-0.000001) { min dist = distance, best fit = l, pπntf("Frame#%d: best fit is frame#%d (%f)\n", frame_no,best_fιt,mιn_dιst); MOVIE getFrame (movie, best_fit,curr_framel); spπntf(temp,"%s.%d.tex",source_movιe_name, best_fit); restoreTexCoord(temp,left_mιh 3ts,πght_mth_pts, left mth tex.πght mth tex), /* Also sets model region vars */ recompute_face(); width = (int)(right_model-left_model), height = (ιnt)(top_model-bottom model), sub img = GιmgCreateSubCopy(curr_framel,(ιnt)left_model, (ιnt)bottom_model,wιdth,heιght), tevdef(l, 0, tevpropsl), GιmgSetAlpha(sub_ιmg,2551), texdef2d(2, 4, wιdth,heιght, (u long *)ImgRast(sub_ιmg), 7, texpropsl), GιmgSetAlpha(sub__mg,2551), texdef2d(3, 4, wιdth,heιght, (u long *)ImgRast(sub_ιmg), 7, texpropsl), GιmgDel(sub ιmg), return (best fit), int msertMouth (int frame no, mt best fit) { mt l, j, k,wιdth,heιght, char temp[MAX_NAME], pπnt "Frame#%d mouth taken from frame#%d\n", frame no, best fit); loadActorLιpsParameters(best fit), DrawScene(), MOVIE getFrame (movie, best_fit,curr_framel), spπntf(temp,"%s %d.tex",source_movιe_name, best fit), restoreTexCoord(temp,left_mth_pts,nght_mth_pts, left_mth_tex,πght_mth_tex), /* Also sets model region vars */ recompute_face(), width = (ιnt)(πght_model-left_model), height = (mt)(top_model-bottom_model), tevdef(l, 0, tevpropsl), sub img =GιmgCreateSubCopy(curr_frame 1 ,(ιnt)left_model, (mt)bottom_model,wιdth,heιght), GιmgSetAlpha(sub_ιmg,2551), texdef2d(2, 4, wιdth,heιght, (u long *)ImgRast(sub_ιmg), 7, texpropsl), GιmgSetAlpha(sub_ιmg,2551), texdef2d(3, 4, wιdth,heιght, (u long *)ImgRast(sub_ιmg), 7, texpropsl), GιmgDel(sub ιmg), return (best fit), void loadParameters(Parameter *left_array, Parameter *nght_array) { mt l, for (ι=0, KMAX_PARAMETERS, ι++) { left_parameter[ι] = left_array[ι], πght_parameter[ι] = πght_array[ι], } float normalιzedParam(Parameter **trans_params, Parameter *source_params, mt frame no, t prm) float res, v, max t, min t, min s, max s, min t = MIN_VAL(trans_params[0][prm]), max t = MAX_VAL(trans_params[0][prm]), min s = MIN_VAL(source_params[prm])*mouth_scale, max s = MAX_VAL(source_params[prm])*mouth_scale, v = (VAL(trans_params[frame_no]tprm])-mιn_t)/(max_t-mm_t), res = v * (max s-min s) + min s, return (res), void smoothLιρsParameters(ιnt frame no, int prm, int range, float *1, float *r, int normalize flag) { float 11 = 0 0, rl = 0 0, mιn_l = SOME_BIG_NUMBER, mιn_r = SOME_BIG_NUMBER, max_l = -SOME_BIG_NUMBER, max_r = -SOME_BIG_NUMBER, float cur l, cur r, mt l, from = MAX(first_frame,frame_no-range), to = MIN(last_frame,frame_no+range), if (normalize flag) { cur l = normahzedParam(left_trans_array,left_source_array[0],frame_no,prm), cur r = normalιzedParam(rιght_trans_array,rιght_source_array[0],frame_no,prm), for (ι=from-frame_no, I <= to-frame_no, ι++) { 11 += normal_zedParam(left_trans_array,left_source_array[0],frame_no+i,prm), r 1 += normalιzedParam(πght_trans_array,πght_source_array [0],frame_no+ι,prm), if (11 > max l) max l = 11 , if (rl > max r) ax r = rl , else { if (prm == MTH_Yscl) { cur l = VAL(left_trans_array[frame_no][prm])*mouth_scale, cur r = VAL(πght_trans_array[frame_no][prm])*mouth_scale, } else { cur l = VAL(left_trans_array[frame_no][prm]), cur r = VAL(πght_trans_array[frame_no][prm]), } for (ι=from-frame_no, I <= to-frame_no, ι++) { if (prm == MTH_Yscl) { 11 += VAL(left_trans_array[frame_no+ι][prm])*mouth_scale, rl += VAL(πght_trans_array[frame_no+ι][prm])*mouth_scale, } else { 11 += VAL(left_trans_array[frame_no+ι][prm]), rl += VAL(rιght_trans_array[frame_no+ι][prm]), } if (11 > max l) max l = 11, *1 = 11 / (to-from+1), *r = rl / (to-from+1), / ******♦»***************************************»**************** void loadTranslatorLιpsParameters(ιnt frame no, mt normahze_params) { float Il,12,13,rl,r2,r3, mt l, prm, int from = MAX(f_rst_frame,frame_no-frame_range), to = MIN(last_frame,frame_no+frame range), for (ι=0, l < XtNumber(whιch_params), ι++) { prm = whιch_params[ι], if (avg_params_flag) smoothLιpsParameters(frame_no,prm, ranges[ι],&12, &r2, normalιze_params), else smoothLιpsParameters(frame_no,prm, 0, &12, &r2, normahze_params), if (prm == MTH_Yscl || prm = MTH NTERP) { if (avg width flag) VAL(left_parameter[prm]) = VAL(nght_parameter[prm]) = (12+r2)/2 0, } else { VAL(left_ρarameter[prm]) = 12, VAL(nght_parameter[prm]) = r2, } PRINTF2("changed to (%f, %f)\n", VAL(left_parameter[prm]), VAL(πght_parameter[prm])) ; if (verbose_mode) pnntf("(% 4f,% 4f)\t",12,r2), if (verbose mode) pπntf("\n"), recompute faceQ, / *********** * ** *• ** • ** ** *** *• ** * ** **** * **•* * * * *•**** ** *••* ** * ** *• **** * ** • *** */ void loadActorLιpsParameters(ιnt frame no) { float H,12,13,rl,r2,r3, for (ι=0, l < XtNumber(whιch_params), ι++) { prm = whιch_params[ι], VAL(left_parameter[prm]) = VAL(left_source_array[frame_no][prm]), VAL(πght_parameter[prm]) = VAL(πght_source_array[frame_no][prm])„ } recompute_face() , > /*****• ******************************* *************************************** / { long nof, /* Num of frames */ char temp[MAX_NAME], lιne[80], mt l, j, last, ong_frame_no,new_frame_no, Gimg small img, grab frame, float pl6[2],p288[2], dιstance,dιstancel,sb, Matrix M, FILE *force_frames, mt compressed image size, *compressed_ιmage, if (force frames flag) { if ((force frames = fopen(force_frames_fϊlename, "r")) == NULL) force frames flag = FALSE, else { fgets (line, 80, force frames), sscanf(hne, "%d\t%d", &oπg_frame_no, &new_frame_no), tm = tιme(0), pπntfι["Start dubbing %d frames at %s",last_frame-fϊrst_frame, cUme(&tm)), readsource(SRC_FRONT), grab frame = GιmgCreate(xsιze,ysιze,GRGBA), MOVIE setCurrentFrameNo (movie, first frame), if (one_frame_mode) { textureMapp g(TEX ON) , DrawScene(), cpack(bgc), for (ι=fιrst frame, j=translator_first_frame, i <= last frame, ι++j++) { tex_mode = TRACK MODE, spnntf(temp, "%s %d prm", source movie name, I), if (One frame mode) loadParameters(left_source_arτay[ι],πght_source_array[ι]), /* else loadParameters(left_source_array[0],πght_source_arτay[0]),*/ else { VAL(left_parameter[BEARD_SCL]) = VAL(πght_parameter[BEARD_SCL]) = 0, recompute_face(), } VAL(left_parameter[BEARD_SCL]) = VAL(nght_parameter[BEARD_SCL]) = 0, recompute_face(), DrawScene(), prepareMatrιx(M), if (put image && !one_frame_mode) { textureMappιng(TEX ON), DrawScene(), loadTranslatorLιpsParameters(ι,normahze_mouth), DrawScene(), calcProjectιon(left_trans_pts,πght_trans_pts), if (mouth_area >= TEX_IN) { if (force frames flag && (l == ong frame no)) { last = msertMouth(oπg_frame_no,new_frame_no), fgets (line, 80, force frames), sscanf(hne, "%d\t%d", &ong_frame_no, &new_frame_no), > else { if (l == fϊrst frame) last = loadMouth(ι,ι), else last = loadMouth(ι,last), else pπntf("Frame#%d\n", l), tex_mode = DUB MODE, recompute_face(), prepareMatπx(M) , DrawScene(), lrectread(0,0,xsize- 1 ,ysize- 1 ,(u_long *)ImgRast(grab_frame)); MO VIE_addCurrentFrame(out_movie 1 ,grab_frame,0); MOVIE_addAudioFrame(audio 1 , out movie 1 ); } else { small img = GimgResize(grab_frame,xsize/2,ysize/2,2); MOVIE_addCurrentFrame(out_movie2,small_img,0); MOVIE addAudioFrame(audio2,out_movie2); GimgFree(small img); } if (put image && lone frame mode) { MOVIE nextFrame(movie); textureMapping(TEX OFF); if (full_flag) { MOVIE_close(out_movie 1 ); out moviel = MOVIE_open(full_dubbed_movie_name); } else { MOVIE_close(out_movie2); out_movie2 = MOVIE open(dubbed movie name); } tm = time(O); AFclosefile(audiol); AFclosefιle(audio2); printf("Finished at %s", ctime(&tm)); /*••************************************************************************ ,' void DrawScene(void) { zclear(); update windo w display ( ) ; } / ************************************* • ***************************** . void ProgUsage(char * filename) { fprintf(stderr,"Dub: fix lips in a dubbed movie.W); fprintf(stderr,"Usage:\n"); fprintf(stderr," %s [options]\n", filename); fprintf(stderr,"\n Options:\n"); fprintf(stderr," -s <movie file>\tSource: movie to be dubbed\n"); fprintf(stderr," -o <movie file>\tOutput movie name (default=\"movie\")\n"); fprintf(stderr," -t <movie file>\tTranslator's movie\n"); fprintf(stderr," -u <filename>\t\tForce usage of info in filename to plant mouth\n"); _printf(stderr," -f <integer>\t\tFirst frame num, starting at 0 (default)\n"); fprintf(stderr," -1 <integer>\t\tLast frame num (default=0)\n"); fprintf(stderr," -F <integer>\t\tTranslator's First frame num (default=0)\n"); fprintf(stderr," -q <integer>\t\tJpeg quality (default=93)\n"); fprintf(stderr," -m <integer>\t\tMouth scale factor (optional)\n"); fprintf(stderr," -r <integer>\t\tRange of frame to search mouth (defalut=25)\n"); fprintf(stderr," -w \t\t\tCreate only Wire frame animation (optional)\n"); fprintf(stderr," -ap \t\t\tAverage params (optional)\n"); fprintf(stderr," -aw \t\t\tAverage mouth width (optional)\n"); fprintf(stderr," -b \t\t\tCreate a full size movie (optional)\n"); fprintf(stderr," -n \t\t\tDon't Normalize mouth\n"); fprintf(stde_τ," -IN \t\t\tUse inside of mouth (default)\n"); fprintf(stderr," -OUT \t\t\tUse outside of mouth\n"); fprintf(stderr," -EXT \t\t\tUse bigger area around mouth\n"); fprintf(stderr," -mc \t\t\tlnside mouth color\n"); fpnntf(stderr," -v \t\t\tVerbose mode\n"); exit(0); /***************************************************************************; main(int argc, char **argv) { XEvent e; char temp[200]; Inιt(argc, argv); UIInit(&argc, argv); draw_poly = 1 ; MOVIE_bmd(movιe, da); MOVIE_setCurrentFrameNo(movie,fϊrst_frame); draw_face(); RedrawNeeded = TRUE; while (XtAρpPending(ac)) { XtAppNextEvent (ac, &e); XtDispatchEvent (&e); } Go(); } / *********************•*********•********•*•****•************************* * Module: general. c * By: Ranco * History: * 18.8.94: creation. ************************************************************************* * #mclude "x_inc.h" #ιnclude "mv.h" #include "general.h" / *********•*••********•***************************************************** Set the proper GL matrices: The transformation that a point p experience is as follows: p * (S * Rx(-90)*Ry(-90)*Rx(90-x)*Ry(-y)Rz) * TRANS * Tnew = (U\ V) •**•****•**************************************************•*************** / void setMatrices(void) { loadmatrix(idmat) ; translate (left_parameter[HEAD_Yoff].value, left_parameter[HEAD_Zoff] .value , left_parameter[HEAD_Xoff].value); rotateAndScale(); } / v***************************************************************,*,,,,,*,,,,*, , void rotateAndScale(voιd) { /* Global transformation- */ /* multmatπx(global trans);*/ rotate((mt)(left 3arameter[POLAR_TWIST].value*10),'z'); rotate(-(ιnt)(left_parameter[POLAR_AZIM].value*10),'y'); rotate(900-(ιnt)(left_parameter[POLAR_INC].value*10),'x'); rotate(-900,'y'), rotate(-900,V); if (which image = SIDE MG) scale(saved_side_sc,saved_side_sc,saved_sιde_sc); else scale(sc,sc,sc); / ********* •* ************** * ** *** ** • * •*** * * ** •** ** * ******* * ****** * *** * *******/ void get_comρosιte_matπx(Matπx M) { Matπx mv; register int ι,j,k; mmode(MVIEWING); getmatπx(mv); /* form product mv * mp ... viewing followed by projection */ for (i=0; ι<4; ι++) { for (k=0; k<4; k++) { M[ι][k] = 0.0; for 0=0; J<4; j++) M[i][k] += mv[ι][j] * mp[j][k]; } ** * ******** * * * ** ** ** ** ** * **** ** ******* * * *** **** •*** ** •*• * • * * ** * * ** * * *** • * • * /* Tipically, both functions above should be called together, and this is */ /* what this function does. */ / ******************************************************* • •** • *** • *********** void prepareMatπx(Matπx M) { setMatπces(), get composite matnx(M); /* View x Projection matrix */ /******•******* γ o r j(j JQ screen coordinates ********************************/ void world2screen(Matrιx M, float x, float y, float z, float *sx, float *sy) { float v[4]; register mt 1, long xs = xsize, ys = ysize, for (ι=0, ι<4, ι++) v[ι] = x*M[0][ι]+y*M[l][ι]+z*M[2][ι]+M[3][ι], ιf (v[3]==0 0) { Bug("w2s v[3] = 0.0"), fprmtf(stderr, "V (%f, %f, %f, %f)\n", v[0], v[l], v[2], v[3]), return; } *sx = ((float)xs/2.0)*(v[0]+1.0)-.5; *sy = ((float)ys/2.0)*(v[l]+1.0)-.5; /************ Returns the distance between 2 points ************************/ float dist (float *pntl, float *pnt2) { return (fsqrt((pntl [0]-pnt2[0]) * (pntl[0]-pnt2[0]) + (pntl [l]-pnt2[l]) * (pntl [l]-pnt2[l]))), float hdist (float *pntl, float *pnt2) { return (fabs(pntl [0]-pnt2[0])); float vdist (float *pntl, float *pnt2) { return (fabs(pntl [l]-pnt2[l])); } /* Matrix utilities */ /********•*•*•**•***********•****************** • ******* • ******************** / void copy matrix (Matrix to, Matrix from) { register int 1, j; for (ι=0; ι<4; ι++) for 0=0; J<4; j++) to[ι][ ] = from[ι][j], } / ******************** • ***•**** • ******** •• **** • ********** • ** • **************** , ' void pπnt_matπx(char *str, Matrix m) { register mt l, j; pnntfTPnnt matrix: %s\n", str); for (ι=0; ι<4, ι++) { for 0=0; j<4; j++) { prmtf("%3.5f ",m[ι][j]); } pπntf("\n"); } / ************************************************************************; void setPolarTwist(float val) { left_parameter[POLAR_TWIST] .value = right_parameter[POLAR_TWIST].value = val; } z* *******************************************************************,,,*** . , void setPolarAzimuth(float val) { left_parameter[POLAR_AZIM]. value = right_parameter[POLAR_AZIM].value = val; } / ******* • * • •*********** • ********** • * ••• ** • ****••*** • *•************•****** / void setPolarInc(float val) { left_parameter[POLAR_INC].value = right_parameter[POLAR_INC].value = val; } . f t********************************************************************** / void addDist2Face(float delta) I 1 sc += delta; / *** • ** • *** • ********************************************** • •************* void addXoff(float delta) { left_parameter[HEAD_Xofϊ]. value = right_parameter[HEAD_Xoff]. value += delta; left_parameter[HEAD_Xofϊ]. changed = right_parameter[HEAD_Xoff). changed = 1 ; } / ***********************************************•***•***********•********, void addYoff(float delta) { left_parameter[HEAD_Yoff). value = nght_parameter[HEAD_Yoff]. value += delta, left_parameter[HEAD_Yofϊ]. changed = πght_parameter[HEAD_Yoff].changed = 1; /***•*********•* • ••******• • •*********************•**•* • ********* • ••****** > void addZoff(float delta) { left_parameter[HEAD_Zofϊ]. value = πght_parameter[HE AD ZoffJ. value += delta; left_parameter[HEAD Zoff]. changed = πght_parameter[HEAD_Zoff). changed = 1; } / ************************************************************************ . . void addPolarTwιst(float delta) . left_parameter[POLAR_TWIST].value = πght_parameter[POLAR_TWIST]. value += delta; left_parameter[POLAR_TWIST].changed = πght_parameter[POLAR_TWIST].changed = 1 , / **************** • *••********** • *************************•*************** / void addPolarAzιmuth( float delta) { left_parameter[POLAR_ AZIM]. value = πghtj3arameter[POLAR_ AZIM] .value += delta; left_parameter[POLAR_ AZIM]. changed = πght_parameter[POLAR_AZIM]. changed = 1 ; / •***************************•******************************************* void addPolarInc(float delta) { left_parameter[POLAR_INC]. value = nght_parameter[POLAR_INC].value += delta; left_parameter[POLAR_INC].changed = πght_ρarameter[POLAR_INC]. changed = 1 ; } / ************************************************************************ void saveTexCoord(char *filename, int np) { FILE *f; char tempfMAX NAME], param file namefMAX NAME]; Matrix M; float p[2],wιdth,heιght; calcTextureCoords(left_tex,nght_tex); spπntf(temp,"%s.tex",filename); unhnk(temp); if ((f = fopen(temp, "w")) == NULL) { fpπntf(stderr, "Can't open texture file '%s' for wπting!", temp); return; } πntf(f, "Num of points: %d\n",np); fpnntf(f, "Region: %f, %f, %f, %f\n", left model, top model, πght model, bottom model); width = (floor)(πght_model-left_model), height = (floor)(top_model-bottom_model); prepareMatπx(M), for(ι=l; K=np; ι++) { world2screen(M, left_pt[ι][0], left_pt[i][l], left_pt[ι][2], &p[0], &p[l]), p[0] = (p[0]-left_model)/width; Pfl] = (p[l]-bottom_model)/heιght; fpπntf(f, "%d\t%f, %f\n",ι,p[0], p[l]); world2screen(M, nghtjpt[ι][0], nght_pt[ι][l], πght_pt[ι][2], &p[0], &p[l]); p[0] = (p[0]-left_model)/width; p[l] = (ptl]-bottom_model)/height; fprmtf(f, "%d\t%f, %f\n",ι,p[0],p[l]); } setPolarInc(90.0), setPolarTwist(00), setPolarAzιmuιh(00), sc = 035, /* Usually it is around this number */ ρrepareMatrιx(M), fpπntf(f, "# Normalized projection of selected points of model:\n"), for(ι=49, K=70, ι++) { world2screen(M, left_pt[ι][0], left_pt[ι][l], left_pt[ι][2], &p[0], &p[l]), fpπntf(f, "%d\t%d, %d\n",ι,(mt)p[0], (ιnt)p[l]), world2screen(M, πght_pt[ι][0], nght_pt[ι][l], πght_pt[ι][2], &p[0], &p[l]), fpπntf(f, "%d\t%d, (ιn.)pfl]), } l = 287, world2screen(M, left_pt[ι][0], left_pt[ι][l], left_pt[ι][2], &p[0], &p[l]), fpπntf(f, "%d\t%0f, %0f\n",ι,p[0]+ 5, ρ[l]+5), world2screen(M, nght_pt[ι][0], rιght_pt[ι][l], πght_pt[ι][2], &p[0], &p[l]), fpπntf(f, "%d\t%0f, %0f\n",ι,p[0]+ 5, p[l]+5), fclose(f), s p r ι n t f ( p a r a m _ f ι l e _ n a m e , " % s % d p r m " , out_base_name,(ιnt)MOVIE_getCurrentFrameNo(movιe)), restoreParameters(param_file_name,left_parameter,πght_parameter,TRUE), /*** * * ** * ** •**•*** *** * * *** ** ** * **** *** ** ** **•* * •***** *** *•*** ** *•* * * * •* **/ void restoreTexCoord(char *filename, float left_pt[][2], float πght_pt[][2], float left_tex[][2], float πght_tex[][2]) { FILE *f, chartemp[MAX_NAME],hne[MAX_LINE], float wιdth,heιght, if ((f = fopen(filename, "r")) == NULL) { spπntf(temp,"%s tex",filename), if ((f = fopen(temp, "r")) == NULL) { fprmtf(stderr, "Can't open texture file '%s' for reading'", filename), return, } fgets(lιne,MAX_LINE,f), sscanf(lιne, "Num of points %d\n",&np), fgets(hne,MAX_LINE,f), sscanf(hne, "Region %f, %f, %f, %f\n", &left_model, &top_model, &nght model, &bottom model). width = (floor)(πght model-left model), height = (floor)(top_model-bottom_model), for(ι=l , ι<=np, ι++) { fgets(lιne,MAX_LINE,f), sscanf(lιne, "%d\t%f, %f\&j,&left_tex[ι][0],&left_tex[ι][l]), fgets(hne,MAX_LINE,f), sscanf(hne, "%d\t%f, %f,&j,&nght_tex[i][0],&nght_tex[i][l]), } fgets(hne,MAX_LINE,f), /* Remark line */ while Ofeofrø) { fgets(lιne,MAX_LINE,f), sscanf(hne, "%d",&j), sscanf(hne, "%*d\t%f, %f',&left_pt[ ][0],&left_pt|j][l]), fgets(hne,MAX_LINE,f), sscanf(hne, "%*d\t%f, %f,&πght_pt[j][0],&nght_pt[)][l]), } fclose(f), *** **** * * • ***************** * *** * *** * ** * **** ** * • * *** *** * * • * * ****** *• ***** / /* Filename should be added " mthl" and " mth2" */ /* Then, inside of mouth (without lips) coordinates are saved m mthl */ /* file, and outside of the moith is saved in mth2 file */ /*********************•*•**********•************************************* / void saveInMth(char *filename) { FILE *f; char temp[MAX_NAME], /* Save inside of mouth */ spπntf(temp, "%s.mthl ", filename), unlιnk(temp); if ((f = fopen(temp, "w")) == NULL) { fpπntf stderr, "Can't open mth param file '%s' for writing!", temp), return; > fpπntf(f, "%f, %f\n",πght_tex[287][0], πght_tex[287][l]); /* 0 */ fpπntf(f, "%f, %f\n",πght_tex[63][0], πght_tex[63][l]); /* 1 */ fpπntf(f, "%f, %f\n",πght_tex[62][0], πght_tex[62][l]), /* 2 */ fpπntf(f, "%f, %f\n",πght_tex[61][0], πght_tex[61][l]); /* 3 */ fprintf(f, "%f, %f\n",left_tex[62][0], left_tex[62][l]), /* 4 */ fprmtfiΥ, "%f, %f\n",left_tex[63][0], left_tex[63][l]); /* 5 */ fprintf(f, "%f, %f\n",left_tex[287][0], left_tex[287][l]); /* 6 •/ fpπntfi , "%{, %f\n",left_tex[60][0], left_text60][l]), /* 7 */ πntf(f, "%f, %f\n",left_tex[59][0], left_tex[59][l]); /* 8 */ fjpπntf(f, "%f, %f\n",left_tex[58][0], left_tex[58][l]), /* 9 */ fpπntf(f, "%f, %f\n",πght_tex[59][0], nght ex[59][l]); /* 10 */ fpπntf(f, "%f, %f\n",πght_tex[60][0], πght_tex[60][l]); /* 11 */ fclose(f); /* Save outside of mouth */ spπntf(temp, "%s.mth2", filename); unhnk(temp); if ((f = fopen(temp, "w")) == NULL) { fpπntfifstderr, "Can't open mth param file '%s' for writing!", temp); return; } fpnntf(f, "%f, %f\n",nght_tex[70][0], πght_tex[70][l]); /* 0 */ fprintf(f, "%f, %f\n",πght_tex[69][0], πght_tex[69][l]); /* 1 */ fpπntf f, "%f, %f\n",nght_tex[68][0], nght_tex[68][l]); /* 2 */ fpπntf(f, "%f, %f\n",πght_tex[67][0], πght_tex[67]tl]), /* 3 */ φπntf(f, "%f, %f\n",left_tex[68][0], left_tex[68][l]), /* 4 */ fprmtf(f, "%f, %f\n",left_tex[69][0], left_tex[69][l]), /* 5 */ fpπntf(f, "%f, %f\n",left_tex[70][0], left_tex[70][l]), /* 6 */ fpπntf(f, "%f, %f\n",left_tex[51][0], left_tex[51][l]), /* 7 */ fpπntf(f, "%f, %f\n",left_tex[50][0], left_tex[50][l]), /* 8 */ fpnntf(f, "%f, %f\n",left_tex[49][0], left_tex[49][l]), /* 9 */ φnntf(f, "%{, %f\n",nght_tex[50][0], nght_tex[50][l]), /* 10 */ φπntf(f, "%f, %f\n",nght_tex[51][0], πght_tex[51][l]), /* 11 */ fclose(f), /* Save external mouth */ spπntf(temp, "%s.mth3", filename), unlιnk(temp), if ((f = fopen(temp, "w")) == NULL) { φπntf(stderr, "Can't open mth param file '%s' for writing'", temp), return, } φnntflff, "%f, %f\n",πght_tex[44][0], πght_tex[44][l]), /• 0 */ φnntπT, "%f, %f\n",πght_tex[73][0], πght_tex[73][l]), /* 1 */ φπntf(f, "%f, πght_tex[72][l]), /* 2 */ fpnntf(f, "%f, %f\n",πght_tex[71][0], πght_tex[71][l]), /* 3 */ φπntf(f, "%f, %f\n",left_tex[72][0], left_tex[72][l]) ( /* 4 */ φπntf(f, "%f, %f\n",left_tex[73][0], left_tex[73][l]), /* 5 */ φπntf(f, "%f, %f\n",left_tex[44][0], left_tex[44][l]), /* 6 */ fprmtf(f, "%f, %f\n",left_tex[43][0], left_tex[43][l]), /* 7 */ fpπntfi[f, "%f, %f\n",left_tex[42][0], left_tex[42][l]), /* 8 */ φπntf(f, "%{, %f\n",left_tex[41][0], left_tex[41][l]), /* 9 */ φnntf(f, "%f, %f\n",πght_tex[42][0], nght_tex[42][l]), /* 10 */ φπntf(f, "%{, %f\n",πght_tex[43][0], nght_tex[43][l]), /* 11 */ fclose(f), } /* **** • * • ** •* * • * * ** **•** ********* * ***************** ** ***** * ***********_(,; int int comp (const void *ιl, const void *ι2) { return (*((ιnt *)ιl) - *((mt *)ι2)); } / ********* * ***** *•• ******* * ********* •* ***** • ********•**•*************** / int readKeyFramelndices (char *filename, mt *key_frames, t *ιnιt_frames) { FILE *f; mt l = 1 ; char temp[MAX_LINE]; key framesfO] = ιnιt_frames[0] = 0; spπntf(temp,"%s.kf',filename); if ((f = fopen(temp, "r")) == NULL) { return (FALSE), } while (fgets(temp,MAX_LINE,f) && !feof(f)) { sscanf(temp, "%d", &key_frames[i]); sscanf(temp, "%d", &ιnιt_frames[ι++]); } fclose(f); key_frames[0] = I- 1 ; qsort (key_frames+l,key_frames[0],sizeof(int),mt_comp); spnntf( temp, "%s. if '.filename), if ((f = fopen(temp, "r")) == NULL) { return (FALSE); > while (fgets(temp,MAX_LINE,f) && !feof(f)) { sscanf(temp, "%d", &mιt_frames[ι++]); } fclose(f); ιnιt_frames[0] = l-l; qsort (ιnιt_frames+l,ιnιt_frames[0],sιzeof(ιnt),mt_comp), pπntf "%d mit frames ",ιnιt_frames[0]), for (ι=l, l <= ιnιt_frames[0], ι++) pπntf ("%d ", ιnιt_frames[ι]), pπntf("\n%d key frames ",key_frames[0]), for (ι=l , l <= key framesfO], ι++) pπntf ("%d ", key_frames[ι]), pπntf("\n"), return (TRUE), } / *****•********••*******•**********•**•**•*******•*•**•*•*********•**** . void restoreInMth(char ""filename, float ιnto[12][2]) { FILE *f, int l, char temp[MAX_LINE], if ((f = fopen(filename, "r")) == NULL) { return, for (ι=0, l < 12, ι++) { fgets(temp,MAX_LINE,f), sscanf(temp, "%f, %f, &mto[ι][0], &mto[ι][l]), } fclose(f), } / ***********************************************************************; void swapParameters(voιd) { int j, if (which image == SIDE IMG) { for 0=0; j < NUM_SAVED; j++) { saved_front_params[0][ ] = VAL(left_parameter[save_those[j]]), saved_front_params[l]|j] = VAL(πght_parameter[save_those[j]]); VAL(left_parameter[save_those[)]]) = saved_side_params[0][|]; VAL(πght_parameter[save_those|j]]) = saved_sιde_params[l][j], else { for 0=0; j < NUM_SAVED; j++) { saved_sιde_params[0] )] = VAL(left_parameter[save_those[j]]), saved_sιde_params[l][j] = VAL(πght_parameter[save_those[j]]); VAL(left_parameter[save_those[j]]) = saved_front_params[0][j], VAL(πght_ρarameter[save_those|j]]) = saved_front_params[l][)]; / ********************************************************************** *^ /* Converts Gimg (unsigned long (RGB)) image to char ""result, which is */ /* The weighted average of the input image. Expects result memory to */ /* be allocated */ /********** • *******************************•*************************** * ;' void longImg2charVec (u long *ιmg, mt sx, int sy, int wιdth,ιnt height, int xsize, char ""result) register mt y, x, dx = xsize - width, lmg += sy*xsιze + sx; for (y=0; y < height; y++) { for (x=0; x < width; x++) { ""result = (char)greyColor(*ιmg); result++; ιmg++, } ;* it*********************************************************************/ void findRegιon(ιnt from vertex, t to vertex, float ""left, float *top, float *πght, float ""bottom, float w scale factor, float h scale factor) { float *u, *d, *1, *r, Matrix M; float temp, float max x, max y, min x, mιn_y, int size, corj, max_x_ι, max_y_ι,mιn_x_ι,mιn_y_ι; float width, heιght,lp[2],φ[2]; max x = -999990, max y = -999999, min x = 99999.0, min y = 99999.9, prepareMatπx(M) , for 0=from_vertex; j <= to vertex; j++) { world2screen(M, left_pt[j][0], left_pt[)][l], left_pt0][2], &lp[0], &lp[l]), world2screen(M, nght_ρt[j][0], nght_pt[)][l], πght_pt[j][2], &φ[0], &φ[l]), if (GT(lp[0], max_x)) { max x = lp[0]; 1 = left_pt[]];max_x_ι=j;} if (GT(φ[0], max x)) { max x = φ[0]; 1 = nght_pt(j];max_x_ι=j;} if (LT(lp[0], min x)) { mm x = lp[0]; r = left_pt[)];mm_x_ι=j;} if (LT(φ[0], min x)) { mm x = φ[0]; r = πght_pt[j];mιn_x_ι=j,} if (GT(lp[l], max y)) { max y = lp[l]; u = left_pt[j];max_y_ι=,} if (GT(φ[l], max_y)) { max y = φ[l]; u = nght_pt(j];max_y_ι=j;} if (LT(lp[l], min y)) { min y = lp[l], d = if (LT(φ[l], mm_y)) { mιn_y = φ[l]; d = nght_pt(j];mm_y_ι=j;} } world2screen(M, r[0], r[l], r[2], left, &temp); world2screen(M, u[0], u[l], u[2], &temp, top), world2screen(M, d[0], d[l], d[2], &temp, bottom), world2screen(M, 1[0], 1[1], 1[2], nght, &temp); width = (*πght) - (*left) + 1 , height = (*top) - (""bottom) + 1; ""left -= width * w scale factor; ""right += width * w scale factor, ♦ top += height * h scale factor; ""bottom -= height * h scale factor; ""left = MAX(l ,(*left)); ""right = MIN(MOVIE_frameWιdth(movιe)-l,(""πght)), *toρ = MIN(MOVIE_frameHeιght( movie)- l,(*top)), ""bottom = MAX( l,(*bottom)), /***•*********************•********************************************** void setModelRegιon(voιd) { findRegιon(l,np, &left_model, &top_model, &πght_model, &bottom_model, 0.0,0.0), left model = floor(left_model); nght model = floor(πght_model+.5); bottom model = floor(bottom model); top_model = floor(top_model+.5); Parameter temp_left[MAX_PARAMETERS], temp_πght[MAX_PARAMETERS], /*****•*•*******•******************************************•**************-,** ' t restoreLipsParameters(int frame no) { float Il,12,13,rl,r2,r3; char temp[MAX_NAME]; mt which[] = {JAW_ROTAΗON,MTH_Yscl,RSE_UPLIP,LWRL_P_FTUCK,MTH_INTERP} ; sprintf(temp,"%s.%d.prm",out_base_name, frame no); if (!restoreParameters(temp,temp_left, temp_right,TRUE)) return (FALSE); for (i=0; i < XtNumber(which); i++) { prm = whιch[i]; VAL(left_parameter[prm]) = VAL(temp_left[prm]); VAL(right_parameter[prm]) = VAL(temp_πght[prm]); . recompute_face(); return (TRUE); **************************************************************************** / void restoreModel(char ""filename) { char temp[MAX_LINE]; FILE *f; int i; float *p; if ((f = fopen(filename, "r")) = NULL) { pπntf("%s not found!\n",filename); re mm; fgets (temp, MAX_LINE, f); for (i=l; i <= np; i++) { fgets (temp, MAX_LINE, f); p = left_mpts[i]; sscanf(temp, "%*d\t%f\t%f\t%f, &p[0], &p[l], &p[2]); fgets (temp, MAX LINE, f); p = right_inpts[i]; sscanf(temp, H % » d\t%f\t%f\t%f\ &p[0], &p[l], &p[2]); } fclose(f); /******************************************************* 4 ,****4 < 4,4,4, 4 , 4 , 4 ,4, 4 ,*4, 4 , 4 , 4 ,4,4, /I void restoreAHParameters(char ""filename, int n frames, Parameter **left_array, Parameter **right_array) { int i, j,prm; char temp[MAX_NAME]; for (i=0; i<n_frames; i++) { MALLOC(left_array[i],MAX_PARAMETERS,Parameter); MALLOC(right_array[i],MAX_PARAMETERS,Parameter); bzero(left_array[i],MAX_PARAMETERS*sizeof(Parameter)); bzero(right_array[i],MAX_PARAMETERS*sizeof(Parameter)); sprintf(temp, "%s.%d.prm", filename, i); restoreParameters(temp,left_array[i],right_array[i],FALSE); if (i==0 && (n_frames > 1)) { for 0=0; j < NUM_ACTIVE_MTH_PARAMS; j++) { prm = active_mth_params[j]; MAX_VAL(left_array[0][prm]) = VAL(left_array[0][prm]); MIN_VAL(left_arraytO][prm]) = VAL(left_array[0][prm]); MAX_VAL(right_array[0][prm]) = VAL(right_array[0][prm]); MIN_VAL(right_array[0][prm]) = VAL(right_array[0][prm]); } } else for 0=0; j< NUM_ACTIVE_MTH_P ARAMS; j++) { prm = active_mth_params[j]; if (GT(VAL(left_array[i][prm]),MAX_VAL(left_array[0][prm]))) MAX_VAL(left_arτay[0][prm]) = VAL(left_arτay[i][prm]); if (LT(VAL(left_arτay[i][prm]), MIN_VAL(left_array[0][prm]))) MIN_VAL(left_array[0][prm]) = VAL(left_array[i][prm]); if (GT(VAL(right_array[ι][prm]), MAX_VAL(right_array[0][prm]))) MAX_VAL(right_array[0][prm]) = VAL(right_array[i][prm]); if (LT(VAL(right_array[i][prm]), MIN_VAL(right_arτay[0][prm]))) MIN_VAL(right_array[0][prm]) = VAL(right_aιτay[i][prm]); / **************************************************************************** void calcProjection(float left_pts[][2], float right_pts[][2]) { register mt j; float x, y, osc= sc, oinc = VAL(left_parameter[POLAR_INC]), otwist = VAL(left_parameter[POLAR_TWIST]), oazim = VAL(left_parameter[POLAR_AZIM]); Matrix M; setPolarInc(90.0); setPolarTwist(O.O); setPolarAzimuth(O.O); sc = 0.35; /* Usually it is around this number... */ recompute_face() ; prepareMatrix(M); for 0=1 ; j <= np; j++) { world2screen(M, left_pt[j][0], left_pt[j][l], left_pt[j][2], &x, &y); left_pts[j][0] = /*floor"7(x); left_pts[j][l] = /*floor*/(y); world2screen(M, right_pt[j][0], right_pt[j][l], nght_pt[j][2], &x, &y); right_pts[j][0] = /""floor*/(x); right_pts[j][l] = /*floor*/(y); } sc = osc; setPolarlnc(oinc); setPolarTwιst(otwιst); setPolarAzιmuth( oazim) ; / ** * ******** • **** • ***********•** • ****** • * • ********* • ***** • ***************** * * / void calcAvg (float left_pts[][2], float nght_pts[][2], float *mid_x, float *mιd_y, index st *pts_ιndex) float x=0., y=0.; int 1; for (ι=0; K NUM_MTH_PTS; ι++) { if (ρts_ιndex[ι].sιde == LEFT PARAMS) x += left_pts[pts_index[i].pnt][0]; y += left_pts[pts_ιndex[ι].pnt][l]; } else { x += πght_pts[pts_ιndex[ι].pnt][0]; y += πght_ptsfpts_ιndex[ι].pnt][l], } *mid_x = x / NUM_MTH_PTS; *mιd_y = y / NUM_MTH_PTS; / ********************************** * ********* * ******** •• ******* • ********* void setMinMax (int ""array) { int nf = array[0], 1, j, k, pnt, first = l,prm; char temp[MAX_NAME]; mdex_st ""indices; float p[2], range; for (ι=l ; l <= nf; ι++) { spπntf(temp,"%s.%d.prm",out_base_name, array[ι]); /* pnntf("Checkιng %s\n",temp);*/ if (!restoreParameters(temp,temp_left, temp_πght,TRUE)) { pnntf "Wamιng: file %s doesn't exist! !!\n", temp); if (ι==first) first++, } else { if (ι==fϊrst) {/* First file sets all max and mm values' */ for 0=0; j< NUM_ACTIVE_MTH_P ARAMS; j++) { prm = actιve_mth_params[j]; MAX_VAL(left_parameter[prm]) = VAL(tempJeft[prm]), MIN_VAL(left_parameter[prm]) = VAL(temρ_left[prm]); MAX_VAL(πght_parameter[prm]) = VAL(temp_nght[prm]); MIN_VAL(πght_parameter[prm]) = VAL(temp_nght[prm]), } } else { for 0=0; j< NUM_ACTIVE_MTH_PARAMS, j++) { prm = actιve_mth_params[]]; if (GT(VAL(temp_left[prm]),MAX_VAL(left_ρarameter[prm]))) MAX_VAL(left jarameter[prm]) = VAL(temp_left[prm]), if (LT(VAL(temp_left[prm]), MIN_VAL(left 3arameter[prm]))) MIN_VAL(leftj3arameter[prm]) = VAL(temp_lefttprm]); if (GT(VAL(temp_nght[prm]), MAX_VAL(πght 3arameter[ρrm]))) MAX_VAL(πght_parameter[prm]) = VAL(temp_πght[prm]), if (LT(VAL(temp_πght[prm]), MIN_VAL(πght_parameter[prm]))) MIN_VAL(πght_parameter[prm]) = VAL(temp_πght[prm]); } pnntffTotal of %d keyframes\n", nf), pπntf("Mιn and Max values \n \n"), for 0=0, J< NUM_ACTIVE_MTH_PARAMS, j++) { prm = actιve_mth_params[)], if (MAX_VAL(nght_parameter[prm]) == MIN_VAL(nght_parameter[prm])) { spπntf(temp,"%s 0 prm",out_base_name), restoreParameters(temp,temp_left, temp_nght,FALSE), MIN_VAL(πght_parameter[prm]) = MIN_VAL(temp_πght[prm]), MIN_VAL(left_parameter[prm]) = MIN_VAL(temp_left[prm]), MAX_VAL(πght_parameter[pτm]) = MAX_VAL(temp_πght[prm]), MAX_VAL(left_parameter[prm]) = MAX_VAL(temp_left[prm]), } range = (MAX_VAL(left_parameter[prm])-MIN_VAL(left_parameter[prm]))""range_hmit, MIN_VAL(left_parameter[prm]) -= range, MAX_VAL(left_parameter[prm]) += range, range=(MAX_VAL(πght_parameter[pπn])-MIN_VAL(πght_parameter[prm]))"'range_lιmιt, MrN_VAL(πght_parameter[prm]) -= range, MAX_VAL(πght_parameter[ρrm]) += range, pπntf("(%d) %s left mm = %f, left max = %f\n\t\t right min = %f, πght max = %f\n", prm, left_parameter[prm] box label, MIN_VAL(left_parameter[prm]), MAX_VAL(left__parameter[prm]), MIN_VAL(πght_parameterfprm]), MAX_VAL(πght_parameter[prm])), / ***************** • *•***************•***•*****************•************** int ιntInArray(ιnt val, mt ""array) int l, n = array [0]; for (ι=l; ι<=n; ι++) if (val == array[ι]) return (TRUE); return (FALSE); / .***************************************** ****************************4 t ** ι float calcBeard (float p288[2]) { float pl6[2], dιstance,sb; Matrix M; prepareMatπx(M), world2screen(M,left_pt[16][0],left_pttl6][l],left_pt[16][2],&pl6[0], &pl6[l]); world2screen(M,left_pt[288][0],left_pt[288][l],left_pt[288][2],&p288[0], &p288[l]); distance = dist (pl6,p288); } /* ***************** ******************************************************* * Module: gimg.h - interface for gimg.c - image utils * By: Ranco * History: * 13.4.94: creation. * 2nd version (MOVIE based): 24.4.95 ft*** ** **** ****** ********************************************************** / #mclude <stdιo h> #ιnclude <stdhb.h> #ιnclude <unιstd.h> #mclude <stπngs.h> #ιnclude <fcntl.h> #ιnclude <getopt.h> #ιnclude <gl/gl.h> #ιnclude <gl/device.h> #ιnclude <gl/ιmage.h> /* defines for image file manipulation */ #define GCMAP 1 #defme GRGB3 #define GRGBA4 typedef unsigned long MPIXEL, typedef unsigned char PELEMENT, #define REDM OxOOOOOOff #defme GRNM OxOOOOffDO #defme BLUM OxOOfϊOOOO #defme ALPM OxffOOOOOO #define red(x) ((x)&REDM) #define green(x) (((x)&GRNM)»8) #defιne blue(x) (((x)&BLUM)»16) #define alpha(x) (((x)&ALPM)»24) typedef struct { unsigned short xsiz, ysiz, zsiz, char *buf, unsigned short type, } GimgRec, *Gιmg, #define ImgXsιze(ι) ((ι)->xsιz) /* num colomns */ #define ImgYsιze(ι) ((ι)->ysιz) /* num rows */ #defme ImgZsιze(ι) ((ι)->zsιz) /* # color bands */ #define ImgRast(ι) (0)->buf) #defϊne ImgType(ι) ((ι)->type) #defιne ImgPιxRGBadd(ι, x, y) ((ι)->buf + ((y)*ImgXsιze(ι)+(x)) #define ImgPιxCMAPadd(ι, x, y) ((ι)->buf+ ((y)*ImgXsιze(ι)+(x)) *sιzeof(short)) #define ImgPιxRGB(ι, x, y) ( ((MPIXEL *)(ι)->buf) [(y)*ImgXsιze(ι)+(x)]) #defme ImgPιxCMAP(ι, x, y) ( ((short *)(ι)->buf) [(y)*ImgXsιze(ι)+(x)]) #defιne ImgInRange(ι, x, y) ((x>=0 0)&&(y>=0 0)&& \ (x<(double)ImgXsιze(ι))&&(y<(double)ImgYsιze(ι))) Gimg GιmgCreate(short xsize, short ysize, int zsize), int GιmgInιt(Gιmg img, short xsize, short ysize, int zsize), int GιmgFree(Gιmg img), int GιmgDel(Gιmg img), Gimg GιmgRead(char *f), int GιmgWπte(Ptr f, Gimg img), void GιmgDιsp(Gιmg img, short xO, short yO), unsigned long GιmgCalcSum(Gιmg img), void GιmgClear(Gιmg img), Gimg GιmgCreateSubCopy(Gιmg ong, int xO, int yO, mt width, int height), Gimg GimgResize (Gimg image, int w, int h, int sample), void GιmgAvg(Gιmg img, long *r, long *g, long *b, mt include zeros), void GιmgMask(Gιmg img, long r, long g, long b, mt xO, t yO, int width, mt height), void GimgSetAlpha (Gimg img, long a), int GιmgFhp(Gιmg img), mt GιmgInterlace(Gιmg origin, Gimg Destination), t GιmgDeInterlace(Gιmg oπgin, Gimg Destination), * ************************************************************************ * Module image c * By Ranco * History * 18 8 94 creation ************************************************************************** / #mclude "mv h" #mclude "defs h" extern long bgc, j* ******************************************************** ****************** void putimage (void) { MOVTE_showFrame(movιe,(MVframe)0), j* ************************************************************************ * Module: IO.C * By: Ranco * History: * 18.8.94: creation. * 2nd version (MOVIE based): 24.4.95 ***********************************************************φ***4,φ**4,4,*φ4,4,* , #ιnclude "hst.h" /**************************************************************4,4,4,4,4, /* Load points info from filename, into PntList PI */ J* ******************************************************* ********** *^ void loadPts (char ""filename, PntList *P1) { FILE *φ; int l, dummy, count = 0; int x, y, res; char name[MAX_NAME]; Point P; if ((φ = fopen (filename, "r")) == NULL) { pπntf("%s\n",filename); PRINT_ERR("Can't find data fϊle\n"); } whιle(!feof(φ)) { if ((res = fscanf(φ, "%d %d %d", &dummy, &x, &y)) '= 3 || (dummy != count+1)) { if (res == -1) break; PPJNT_ERR("Wrong points file foπnat!\n"); } count++; } *P1 = createPntLιst(); fseek(φ,0,0); for (1 = 0; l < count; ι++) { if (fscanf(φ, "%d %d %d", &dummy, &x, &y) '= 3 || (dummy != ι+l)) { PRINT ERRfWrong points file format!\n"), } P.x = (double)x, P y = (double)y; addPoιnt(*Pl, &P); } fclose(φ); } I* ************************************************************** ********** * Module: hst.h - interface for list c * By- Ranco * History * 16.2.94. creation. **************************************************************************/ #mclude <stdhb.h> #ιnclude <stdιo.h> #ιnclude <math.h> #ιnclude "defs.h" #define NUM OF PNTS(pl) ((pl)->Sιze) #defme POINT(pl,p) ((pl)->Poιnts[p]) #define NUM_OF_LINES(ll) ((ll)->Sιze) #define LINE(ll,p) ((ll)->Lιnes[p]) /* Some point operations */ #define SIZE(p) (XCOR(p)*XCOR(p)+YCOR(p)*YCOR(p)) #define SetPomt(p,a,b) {(p).x = (a); (p) y = (b); } #define GetPomt(p,r) {(r) x=(p).x; (r).y=(p).y; } #define AddPoιnts(p,pl,p2) {(p).x = (pl).x+(p2).x; (p).y = (pl).y+(p2).y; } #define SubPomts(p,pl,p2) {(p).x = (pl).x-(p2).x; (p).y = (pl).y-(p2).y; } #define MulPoιnt(p,c) {(p).x *= (float) (c); (p).y *= (float) (c); } #define DιvPomt(p,c) {(p).x /= (float) (c); (p).y /= (float) (c); } #define DotProduct(pl,p2) ((pl).x*(p2).x+(pl).y*(p2).y) #define SetLιne(l,pl,p2) {(l).Pl .x = (pl)->x; (l).Pl .y = (pl)->y; \ (l).P2.x = ( P 2)->x; (l).P2.y = (p2)->y; } typedef struct { float x, y; } Point; typedef struct { mt Size; Point ""Points; } PntList st; typedef PntLιst_st ""PntList; typedef struct { Point PI, P2; int len, } Lme, typedef struct { int Size; Line *Lmes; } LineList st; typedef LineList st ""LineList, /* Prototypes */ PntList createPntList (void) ; void freePntList (PntList 1) ; PntList addPoint (PntList 1, Point *p) , LineList createLineList (void) , void freeLmeList (LmeList 1) ; LineList addLine (LmeList 1, Point *P1, Point *P2), /* /* File: mv.h */ /* /* Include file for the interface to movie (mv) library /* */ /* Wπtten by: Ranco */ /* Creation: Wed, 5/4/95 */ /* #ifndef _MV_H #define MV H #ιnclude <dmedιa/cl.h> #include <dmedia/cl_cosmo.h> #ιnclude <movie.h> #include "gimg.h" include "defs.h" #mclude <audiofile.h> #define MOVIE_ERR 0 #define MOVIE OK 1 typedef struct { char file_name[MAX_NAME]; MVid movie, imagetrack, audiotrack; int width, height; /* Size of a movie frame */ int interlace; MVframe first, last; /* First and last frame's indices, for playback */ MVframe num frames; MVframe current_frame_no; double frame rate; double audio rate; int audio width; char compressιon[20]; CLhandle compressor, decompressor; mt cosmo available; int paramBufJlO]; mt n_params, Gimg current frame, int del img, /* a flag that indicate if current frame should be freed at the end "7 int oπentation; int quality, /* Jpeg Quality (0 - 100) */ } Movie st; typedef Movie st ""Movie, /********* \iACROS ************/ #define MOVIE movιeName(mv) (mv->file_name) #defιne MOVIE movιeTrack(mv) (mv->movιe) #defιne MOVIE ιmageTrack(mv) (mv->ιmagetrack) #defϊne MOVIE audιotrack(mv) (mv->audιotrack) #define MOVIE_frameWιdth(mv) (mv->wιdth) #define MOVIE frameHeιght(mv) (mv->heιght) #defϊne MOVIE numOfFrames(mv) (mvGetTrackLength(mv->ιmagetrack)) #defιne MOVIE frameRate(mv) (mv->frame_rate) #defme MOVIE_audιoRate(mv) (mv->audιo_rate) #define MOVIE_audιoWιdth(mv) (mv->audιo_wιdth) #define MOVIE firstFrame(mv) (mv->fιrst) #define MOVIE lastFrame(mv) (mv->last) #defme MOVIE getCurrentFrameNo(mv) (mv->current_frame_no) #defιne MOVIE currentFrame(mv) (mv->current_frame) #define MOVIE loadCurrentFrame(mv) (MOVIE_getCurrentFrame(mv,mv->current_frame)) #define MOVIE frameOπentatιon(mv) (mv->oπentatιon) #define MOVIE_frameCompressιon(mv) (mv->compressιon) #define MOVIE framelnterlace(mv) (mv->ιnterlace) #define MOVIE pegQualιty(mv) (mv->quahty) / ********************************************************************** / extern Movie movie; /* Currently allow one movie in the application' */ /*** p ro totypes ***/ Movie MOVIE open (char ""filename), DMparams *MOVIE_ιnιt (Movie mv, char ""filename, mt width, mt height, double frame rate, double audio rate, mt orientation, char ""compression, t interlace); Movie MOVIE create (char ""filename, mt width, int height, double frame rate, double audio rate, int oπentation, char ""compression, int interlace, int jpeg_quahty); mt MOVIE addFrame (Movie mv, MVframe index, Gimg frame, int size); mt MOVIE copyFrames (Movie from mv, Movie to mv, MVframe from index, MVframe to index, MVframe count); t MOVIE deleteFrames (Movie mv, MVframe index, MVframe count); int MOVIE getFrame (Movie mv, MVframe index, Gimg frame); int MOVIE setCurrentFrameNo(Movιe mv, MVframe index), int MOVIE getCurrentFrame (Movie mv, Gimg frame), int MOVIE addCurrentFrame (Movie mv, Gimg frame, mt size), int MOVIE nextFrame (Movie mv); int MOVIE_prevFrame (Movie mv), int MOVIE showFrame (Movie mv, MVframe frame no), mt MOVIE nnd (), mt MOVIE_play (Movie mv), int MOVIE stop (Movie mv), int MOVIE home (Movie mv); mt MOVIE_end(Movιe mv), mt MOVIE_setStartFrame(Movιe mv, MVframe frame no), int MOVIE_setEndFrame(Movιe mv, MVframe frame no), int MOVIE close (Movie mv); size t MOVIE_getFrameSιze (Movie mv, mt frame no); Gimg MOVIE resize (Gimg image, mt w, int h, mt sample), mt MOVIE addAudioFrame (AFfilehandle audioFile, Movie to mv); AFfilehandle MOVIE createAudioTrack (char ""audio file name, Movie to_mv); #endιf /* ************************************************************************ * Module: texture.c * By: Ranco * History: * 18.8.94: creation. ************************************************************************** #mclude "texture.h" #ιnclude "x inc.h" #ιnclude "general.h" #ιnclude "mam.h" #ιnclude "vars.h" #ιnclude "mv.h" float texprops[] = { TX_MINFILTER, TX_POINT, TX MAGFILTER, TX_POINT, /* TX_MINFILTER, TX_BILINEAR, TX MAGFILTER, TX_BILINEAR,"7 TX WRAP, TX_CLAMP, TX_NULL} ; float tevprops[] = {TV_DECAL, TV NULL} , extern int texture map; ^********************************************************************** / void textureMapping (mt op) { long xs,ys; Gimg sub img; mt wιdth,heιght; if (op == TEX_ON) { texture map = TRUE, wire = FALSE, if ('show coord) { MOVIE loadCurrentFrame (movie), calcTextureCoords(left_tex,πght_tex), width = (ιnt)(πght_model-left_model), height = (ιnt)(top_model-bottom_model), s u b i m g GιmgCreateSubCopy(MOVIE_currentFrame(movιe),(ιnt)left_model,(ιnt)bottom_model,wιdth, height), zclear(), if (whιch_ιmage == SIDE_IMG) { xs = ImgXsιze(sιde ιmg), ys = ImgYsιze(sιde ιmg), texdef2d(l, 4, xs, ys, (u long *)ImgRast(sιde_ιmg), 0, texprops), else { GιmgSetAlpha(sub_ιmg,2551), texdef2d(l , 4, wιdth,heιght, (u long "")ImgRast(sub_ιmg), 0, texprops), } tevdef(l, 0, tevprops), tevbmd(TV_ENV0, 1), texbmd(TX_TEXTURE_0, 1), GιmgDel(sub ιmg), } else { texture map = FALSE, tevbind(TV_ENV0, 0), texbind(TX_TEXTURE_0,0), RefreshQ, } RedrawNeeded = TRUE; ********************************************************************** void calcTextureCoords(float left_tex[][2], float πght_tex[][2]) { register int j; float xs, ys,l=0.0,b=0.0; Matπx M, setModelRegιon(); /* Set global left/πght/top/bottom model to the current model's region */ if (which image == SIDE IMG) { xs = (float)(lmgXsιze(sιde_ιmg)), ys = (float)(ImgYsιze(sιde_ιmg)); } else { xs = πght model-left model- 1 , /* IMPORTANT!: we assume "" model is a rectangle around */ ys = top_model-bottom_model-l , /* the current projection of the model */ 1 = left model, b = bottom model; recompute_face() , prepareMatπx(M); for O=l ; j <= np; ++) { world2screen(M, left_pt[j][0], left_pt[j][l], left_pt[j][2], &left_tex[)][0], &left_tex[j][l]); left_tex[]][0] = (left_tex[)][0]-l)/xs; left_tex[]][l] = (left_tex[]][l]-b)/ys, PRINTF5("%d: l,b=% lf,%.lf. tex=%f, %f\n",j,l,b,left_tex[j][0],left_tex[j][l]); world2screen(M, πght_pt[j][0], πght_pt[j][l], πght_pt[j][2], &πght_tex[j][0], &nght_tex|j][l]); right_tex[j][0] = (right_tex|j][0]-l)/xs; right_tex[j][l] = (right_tex[j][l]-b)/ys;

Claims: CLAIMS 1. A method for automated computerized audio visual dubbing of movies comprising of the steps: (a) selecting from the movie a frame having a picture, preferably frontal, of the actor's head and, if available, a frame with its side profile; (b) marking on the face several significant feature points and measuring their locations in the frame; (c) fitting a generic three-dimensional head model to the actor's two-dimensional head picture by adapting the data of the significant feature points, as measured in stage (b), to their location in the model; (d) tracking of the said fitted three- dimensional head model parameters throughout the movie, from one frame to its successor, iteratively in an automated computerized way and creating a library of reference similarity frames ; (e) taking a movie of a dubber wherein the dubber speaks the target text; (f) repeating stages (a), (b), (c), and (d) with the dubber; (g) normalizing the dubber'ε minimum and maximum values of each parameter to the actor's minimum and maximum values for the same parameters; (h) mapping, on a frame to frame basis, the two-dimensional actors face onto its three- dimensional head model by using a texture mapping technique, making use of reference similarity frames; (i) changing the texture mapped three- dimensional model obtained in stage (h) by replacing, on a frame to frame basis, the original mouth parameterε with the mouth parameterε aε computed in stage (d) for the dubber and obtaining the parametric description for the new picture, with identical values to the original, except that the actor's mouth status resembles the mouth status of the dubber; (j) texture mapping the lips area of the same actor from a frame in the movie, with identical or very similar mouth status to the desired new mouth status, onto the lips area of the actor'ε head model for the current frame and then projecting the lips area from the actor's head model onto the current new frame (an optional stage). 2. A method according to claim l wherein the parameters for controlling the three-dimensional head model are the position, orientation, and expression of the head model mouth. 3. A method according to claim l wherein the significant feature points on the face marked on stage b are the eye corners, the mouth corners, and the top and bottom of the face. 4. A method according to claim l wherein about 15 significant feature points on the face are used in the tracking stage. 5. A method according to claim l wherein the movie to be audio visually dubbed is a sequence of one or more still photographs which are identically duplicated, frame after frame, to create a portion of a movie. 6. A method according to claim 5 for audio visual dubbing of still photographs in TV programs such as news from field correspondents. 7. A method according to claim 5 wherein the actor does not speak such as a baby or a mute person. 8. A method according to claim 1 wherein the original movie is an animated cartoon. 9. A method according to claim 8 wherein the actor is an animal or any other non-human or non-living object. 10. A method according to claim 1 wherein the movies are advertisment movies. 11. A method according to claim l wherein the pictures of the movie and of the still photos are in electronic digital form. 12. A method according to claim 1 wherein the pictures are translated into digital form, manipulated in digital form, and returned back to any desired form. 13. A method according to claims 8 wherein the production of an annimated cartoon iε assisted by drawing a straight line segment for the actor's mouth, drawing a small actor'ε picture dictionary containing representive reference similarity frames with completely drawn mouths, and then allowing these lip-line segments to be replaced with the coresponding lip shapes of the dubber as are to be found in the actor's picture dictionary. 14. A method according to claim 1 wherein the "movie" is a painting, a drawing, or a picture. 15. A method according to claim l for creating new movies or new portions of movies from a library of reference frames. 16. A method according to claim 1 for the conversion of background narrative, or any spoken text, to an audio visual form. 17. A method according to claim l wherein the dubber speaks the target text in either another language or the same language and the movie of the dubber is taken while the dubber performs a routine dubbing adaptation of the original into target text. 18. A method for creation of a library of reference similarity frames in the method as defined in claim 1. 19. A method according to claim 1 wherein the automated computerised audio visual dubbing of movies iε done by the software, aε shown in Appendix 1, or by similar software. 20. A software for use in the method aε defined in claim 1. 21. A movie prepared by the automated audio visual dubbing method as defined in the preceeding claims. 22. A movie according to claim 22 wherein the movie is a video movie. 23. A method substantially as herein before described and illustrated.

Inventors: AVNIR DAVID, COHEN RAN, PELEG SHMUEL, AVNIR, DAVID, COHEN, RAN, PELEG, SHMUEL
Applicants: AVNIR DAVID, COHEN RAN, FACE IMAGING LTD, PELEG SHMUEL, AVNIR, DAVID, COHEN, RAN, FACE IMAGING LTD., PELEG, SHMUEL
Application year: 1996
Main classification: G11B31
IPC codes: G06T1, G06T17, G11B27, H04N5, H04N7