Ticket #10793: logodetector.patch

File logodetector.patch, 27.6 KB (added by bryan@…, 7 years ago)

LogoDetector? changes

  • mythtv/libs/libmythtv/avformatdecoder.cpp

    diff --git a/mythtv/libs/libmythtv/avformatdecoder.cpp b/mythtv/libs/libmythtv/avformatdecoder.cpp
    index 9439d39..3c95424 100644
    a b void AvFormatDecoder::InitVideoCodec(AVStream *stream, AVCodecContext *enc, 
    13721372            }
    13731373
    13741374            if (FlagIsSet(kDecodeLowRes))
    1375                 enc->lowres = 2; // 1 = 1/2 size, 2 = 1/4 size
     1375            {
     1376                if (enc->height > 720)
     1377                    enc->lowres = 2; // 2 = 1/4 size
     1378                else
     1379                    enc->lowres = 1; // 1 = 1/2 size
     1380            }
    13761381        }
    13771382        else if (CODEC_ID_H264 == codec->id)
    13781383        {
  • mythtv/programs/mythcommflag/ClassicCommDetector.cpp

    diff --git a/mythtv/programs/mythcommflag/ClassicCommDetector.cpp b/mythtv/programs/mythcommflag/ClassicCommDetector.cpp
    index 800e83d..bb83323 100644
    a b ClassicCommDetector::ClassicCommDetector(SkipType commDetectMethod_in, 
    152152    preRoll(0),                                postRoll(0)
    153153{
    154154    commDetectBorder =
    155         gCoreContext->GetNumSetting("CommDetectBorder", 20);
     155        gCoreContext->GetNumSetting("CommDetectBorder", 5);
    156156    commDetectBlankFrameMaxDiff =
    157157        gCoreContext->GetNumSetting("CommDetectBlankFrameMaxDiff", 25);
    158158    commDetectDarkBrightness =
    void ClassicCommDetector::Init() 
    206206            .arg(width).arg(height)
    207207            .arg(player->GetFrameRate()).arg(commDetectMethod));
    208208
    209     if ((width * height) > 1000000)
    210     {
    211         horizSpacing = 10;
    212         vertSpacing = 10;
    213     }
    214     else if ((width * height) > 800000)
    215     {
    216         horizSpacing = 8;
    217         vertSpacing = 8;
    218     }
    219     else if ((width * height) > 400000)
    220     {
    221         horizSpacing = 6;
    222         vertSpacing = 6;
    223     }
    224     else if ((width * height) > 300000)
    225     {
    226         horizSpacing = 6;
    227         vertSpacing = 4;
    228     }
    229     else
    230     {
    231         horizSpacing = 4;
    232         vertSpacing = 4;
    233     }
     209    horizSpacing = 1;
     210    vertSpacing = 1;
    234211
    235212    LOG(VB_COMMFLAG, LOG_INFO,
    236213        QString("Using Sample Spacing of %1 horizontal & %2 vertical pixels.")
  • mythtv/programs/mythcommflag/ClassicLogoDetector.cpp

    diff --git a/mythtv/programs/mythcommflag/ClassicLogoDetector.cpp b/mythtv/programs/mythcommflag/ClassicLogoDetector.cpp
    index f961af0..6db9e12 100644
    a b  
    66
    77// MythTV headers
    88#include "mythcorecontext.h"
    9 #include "mythplayer.h"
     9#include "mythcommflagplayer.h"
    1010
    1111// Commercial Flagging headers
    1212#include "ClassicLogoDetector.h"
    1313#include "ClassicCommDetector.h"
    14 
    15 typedef struct edgemaskentry
    16 {
    17     int isedge;
    18     int horiz;
    19     int vert;
    20     int rdiag;
    21     int ldiag;
    22 }
    23 EdgeMaskEntry;
    24 
     14#include <ffmpeg-mmx.h>
     15#include <lzoconf.h>
    2516
    2617ClassicLogoDetector::ClassicLogoDetector(ClassicCommDetector* commdetector,
    2718                                         unsigned int w, unsigned int h,
    ClassicLogoDetector::ClassicLogoDetector(ClassicCommDetector* commdetector, 
    2920                                         unsigned int xspacing_in,
    3021                                         unsigned int yspacing_in)
    3122    : LogoDetectorBase(w,h),
    32       commDetector(commdetector),                       frameNumber(0),
    33       previousFrameWasSceneChange(false),
    34       xspacing(xspacing_in),                            yspacing(yspacing_in),
    35       commDetectBorder(commdetectborder_in),            edgeMask(new EdgeMaskEntry[width * height]),
    36       logoMaxValues(new unsigned char[width * height]), logoMinValues(new unsigned char[width * height]),
    37       logoFrame(new unsigned char[width * height]),     logoMask(new unsigned char[width * height]),
    38       logoCheckMask(new unsigned char[width * height]), tmpBuf(new unsigned char[width * height]),
    39       logoEdgeDiff(0),                                  logoFrameCount(0),
    40       logoMinX(0),                                      logoMaxX(0),
    41       logoMinY(0),                                      logoMaxY(0),
    42       logoInfoAvailable(false)
     23      commDetector(commdetector), commDetectBorder(commdetectborder_in),
     24      logoInfoAvailable(false),   logoEdgeDiff(0),
     25      logoMinX(0),                logoWidth(0),
     26      logoMinY(0),                logoHeight(0)
    4327{
    4428    commDetectLogoSamplesNeeded =
    4529        gCoreContext->GetNumSetting("CommDetectLogoSamplesNeeded", 240);
    unsigned int ClassicLogoDetector::getRequiredAvailableBufferForSearch() 
    6347void ClassicLogoDetector::deleteLater(void)
    6448{
    6549    commDetector = 0;
    66     if (edgeMask)
    67         delete [] edgeMask;
    68     if (logoFrame)
    69         delete [] logoFrame;
    70     if (logoMask)
    71         delete [] logoMask;
    72     if (logoCheckMask)
    73         delete [] logoCheckMask;
    74     if (logoMaxValues)
    75         delete [] logoMaxValues;
    76     if (logoMinValues)
    77         delete [] logoMinValues;
    78     if (tmpBuf)
    79         delete [] tmpBuf;
    80 
     50   
    8151    LogoDetectorBase::deleteLater();
    8252}
    8353
    bool ClassicLogoDetector::searchForLogo(MythPlayer* player) 
    8858    long long seekFrame;
    8959    int loops;
    9060    int maxLoops = commDetectLogoSamplesNeeded;
    91     EdgeMaskEntry *edgeCounts;
    92     unsigned int pos, i, x, y, dx, dy;
    93     int edgeDiffs[] = {5, 7, 10, 15, 20, 30, 40, 50, 60, 0 };
    94 
    95 
     61    const int edgeDiffs[] = {55, 25, 13, 6, 0};
     62   
    9663    LOG(VB_COMMFLAG, LOG_INFO, "Searching for Station Logo");
    9764
    9865    logoInfoAvailable = false;
    9966
    100     edgeCounts = new EdgeMaskEntry[width * height];
     67    int *edgeCounts = new int[width * height];
    10168
    102     for (i = 0; edgeDiffs[i] != 0 && !logoInfoAvailable; i++)
     69    for (int i = 0; edgeDiffs[i] != 0 && !logoInfoAvailable; i++)
    10370    {
    10471        int pixelsInMask = 0;
    10572
    10673        LOG(VB_COMMFLAG, LOG_INFO, QString("Trying with edgeDiff == %1")
    10774                .arg(edgeDiffs[i]));
    10875
    109         memset(edgeCounts, 0, sizeof(EdgeMaskEntry) * width * height);
    110         memset(edgeMask, 0, sizeof(EdgeMaskEntry) * width * height);
     76        memset(edgeCounts, 0, sizeof(int) * width * height);
     77        edgeMask.clear();
    11178
    11279        player->DiscardVideoFrame(player->GetRawVideoFrame(0));
    11380
    bool ClassicLogoDetector::searchForLogo(MythPlayer* player) 
    11582        seekFrame = commDetector->preRoll + seekIncrement;
    11683        while(loops < maxLoops && !player->GetEof())
    11784        {
    118             VideoFrame* vf = player->GetRawVideoFrame(seekFrame);
    119 
    12085            if ((loops % 50) == 0)
    12186                commDetector->logoDetectorBreathe();
    12287
     88            if (!commDetector->fullSpeed)
     89                usleep(10000);
     90           
     91            VideoFrame* vf = player->GetRawVideoFrame(seekFrame);
     92            DetectEdges(vf, edgeCounts, edgeDiffs[i]);
     93            player->DiscardVideoFrame(vf);
     94           
    12395            if (commDetector->m_bStop)
    12496            {
    125                 player->DiscardVideoFrame(vf);
    12697                delete[] edgeCounts;
    12798                return false;
    12899            }
    129 
    130             if (!commDetector->fullSpeed)
    131                 usleep(10000);
    132 
    133             DetectEdges(vf, edgeCounts, edgeDiffs[i]);
    134 
     100           
    135101            seekFrame += seekIncrement;
    136102            loops++;
    137 
    138             player->DiscardVideoFrame(vf);
    139         }
    140 
    141         LOG(VB_COMMFLAG, LOG_INFO, "Analyzing edge data");
    142 
    143 #ifdef SHOW_DEBUG_WIN
    144         unsigned char *fakeFrame;
    145         fakeFrame = new unsigned char[width * height * 3 / 2];
    146         memset(fakeFrame, 0, width * height * 3 / 2);
    147 #endif
    148 
    149         for (y = 0; y < height; y++)
    150         {
    151             if ((y > (height/4)) && (y < (height * 3 / 4)))
    152                 continue;
    153 
    154             for (x = 0; x < width; x++)
    155             {
    156                 if ((x > (width/4)) && (x < (width * 3 / 4)))
    157                     continue;
    158 
    159                 pos = y * width + x;
    160 
    161                 if (edgeCounts[pos].isedge > (maxLoops * 0.66))
    162                 {
    163                     edgeMask[pos].isedge = 1;
    164                     pixelsInMask++;
    165 #ifdef SHOW_DEBUG_WIN
    166                     fakeFrame[pos] = 0xff;
    167 #endif
    168 
    169                 }
    170 
    171                 if (edgeCounts[pos].horiz > (maxLoops * 0.66))
    172                     edgeMask[pos].horiz = 1;
    173 
    174                 if (edgeCounts[pos].vert > (maxLoops * 0.66))
    175                     edgeMask[pos].vert = 1;
    176 
    177                 if (edgeCounts[pos].ldiag > (maxLoops * 0.66))
    178                     edgeMask[pos].ldiag = 1;
    179                 if (edgeCounts[pos].rdiag > (maxLoops * 0.66))
    180                     edgeMask[pos].rdiag = 1;
    181             }
    182         }
    183 
    184         SetLogoMaskArea();
    185 
    186         for (y = logoMinY; y < logoMaxY; y++)
    187         {
    188             for (x = logoMinX; x < logoMaxX; x++)
    189             {
    190                 int neighbors = 0;
    191 
    192                 if (!edgeMask[y * width + x].isedge)
    193                     continue;
    194 
    195                 for (dy = y - 2; dy <= (y + 2); dy++ )
    196                 {
    197                     for (dx = x - 2; dx <= (x + 2); dx++ )
    198                     {
    199                         if (edgeMask[dy * width + dx].isedge)
    200                             neighbors++;
    201                     }
    202                 }
    203 
    204                 if (neighbors < 5)
    205                     edgeMask[y * width + x].isedge = 0;
    206             }
    207103        }
     104       
     105        player->DiscardVideoFrame(player->GetRawVideoFrame(0));
    208106
    209         SetLogoMaskArea();
     107        pixelsInMask = AnalyzeEdgeCounts(edgeCounts, maxLoops * 2 / 3);
     108       
    210109        LOG(VB_COMMFLAG, LOG_INFO,
    211             QString("Testing Logo area: topleft (%1,%2), bottomright (%3,%4)")
     110            QString("Testing Logo area: topleft (%1,%2), size (%3,%4)")
    212111                .arg(logoMinX).arg(logoMinY)
    213                 .arg(logoMaxX).arg(logoMaxY));
    214 
    215 #ifdef SHOW_DEBUG_WIN
    216         for (x = logoMinX; x < logoMaxX; x++)
    217         {
    218             pos = logoMinY * width + x;
    219             fakeFrame[pos] = 0x7f;
    220             pos = logoMaxY * width + x;
    221             fakeFrame[pos] = 0x7f;
    222         }
    223         for (y = logoMinY; y < logoMaxY; y++)
    224         {
    225             pos = y * width + logoMinX;
    226             fakeFrame[pos] = 0x7f;
    227             pos = y * width + logoMaxX;
    228             fakeFrame[pos] = 0x7f;
    229         }
    230 
    231         comm_debug_show(fakeFrame);
    232         delete [] fakeFrame;
     112                .arg(logoWidth).arg(logoHeight));
    233113
    234         cerr << "Hit ENTER to continue" << endl;
    235         getchar();
    236 #endif
    237         if (((logoMaxX - logoMinX) < (width / 4)) &&
    238             ((logoMaxY - logoMinY) < (height / 4)) &&
    239             (pixelsInMask > 50))
     114        if (pixelsInMask > 100 &&
     115            (logoWidth < (width / 6) || logoHeight < (height / 6)))
    240116        {
    241117            logoInfoAvailable = true;
    242118            logoEdgeDiff = edgeDiffs[i];
    bool ClassicLogoDetector::searchForLogo(MythPlayer* player) 
    245121                QString("Using Logo area: topleft (%1,%2), "
    246122                        "bottomright (%3,%4)")
    247123                    .arg(logoMinX).arg(logoMinY)
    248                     .arg(logoMaxX).arg(logoMaxY));
     124                    .arg(logoWidth).arg(logoHeight));
    249125        }
    250126        else
    251127        {
    bool ClassicLogoDetector::searchForLogo(MythPlayer* player) 
    254130                        "bottomright (%3,%4), pixelsInMask (%5). "
    255131                        "Not within specified limits.")
    256132                    .arg(logoMinX).arg(logoMinY)
    257                     .arg(logoMaxX).arg(logoMaxY)
     133                    .arg(logoWidth).arg(logoHeight)
    258134                    .arg(pixelsInMask));
    259135        }
    260136    }
    bool ClassicLogoDetector::searchForLogo(MythPlayer* player) 
    263139
    264140    if (!logoInfoAvailable)
    265141        LOG(VB_COMMFLAG, LOG_NOTICE, "No suitable logo area found.");
    266 
    267     player->DiscardVideoFrame(player->GetRawVideoFrame(0));
     142    else
     143        DumpLogo();
     144   
    268145    return logoInfoAvailable;
    269146}
    270147
    271 
    272 void ClassicLogoDetector::SetLogoMaskArea()
     148int ClassicLogoDetector::AnalyzeEdgeCounts(int *edgeCounts, int threshold)
    273149{
    274     LOG(VB_COMMFLAG, LOG_INFO, "SetLogoMaskArea()");
    275 
     150    const int minNeighbors = 2;
     151    int pixelsInMask = 0;
     152    unsigned int logoMaxX = 0, logoMaxY = 0;
     153   
    276154    logoMinX = width - 1;
    277     logoMaxX = 0;
    278155    logoMinY = height - 1;
    279     logoMaxY = 0;
    280 
     156   
     157    LOG(VB_COMMFLAG, LOG_INFO, "Analyzing edge data");
     158   
     159    QBitArray tmpMask(width*height);
     160   
    281161    for (unsigned int y = 0; y < height; y++)
    282162    {
    283163        for (unsigned int x = 0; x < width; x++)
    284164        {
    285             if (edgeMask[y * width + x].isedge)
     165            unsigned int pos = y * width + x;
     166            if (edgeCounts[pos] < threshold)
     167                continue;
     168           
     169            int neighbors = 0;
     170           
     171            // 3x3 block
     172            for (int dy = y - 1; dy <= (y + 1); dy++)
     173            {
     174                for (int dx = x - 1; dx <= (x + 1); dx++)
     175                {
     176                    unsigned int dp = dy * width + dx;
     177                    if (edgeCounts[dp] >= threshold)
     178                    {
     179                        neighbors++;
     180                        if (neighbors > minNeighbors)
     181                            break;
     182                    }
     183                }
     184            }
     185           
     186            if (neighbors > minNeighbors)
    286187            {
     188                tmpMask[pos] = true;
     189               
     190                pixelsInMask++;
     191               
    287192                if (x < logoMinX)
    288193                    logoMinX = x;
    289194                if (y < logoMinY)
    void ClassicLogoDetector::SetLogoMaskArea() 
    293198                if (y > logoMaxY)
    294199                    logoMaxY = y;
    295200            }
    296         }
    297     }
    298 
    299     logoMinX -= 5;
    300     logoMaxX += 5;
    301     logoMinY -= 5;
    302     logoMaxY += 5;
    303 
    304     if (logoMinX < 4)
    305         logoMinX = 4;
    306     if (logoMaxX > (width-5))
    307         logoMaxX = (width-5);
    308     if (logoMinY < 4)
    309         logoMinY = 4;
    310     if (logoMaxY > (height-5))
    311         logoMaxY = (height-5);
    312 }
    313 
    314 void ClassicLogoDetector::SetLogoMask(unsigned char *mask)
    315 {
    316     int pixels = 0;
    317 
    318     memcpy(logoMask, mask, width * height);
    319 
    320     SetLogoMaskArea();
    321 
    322     for(unsigned int y = logoMinY; y <= logoMaxY; y++)
    323         for(unsigned int x = logoMinX; x <= logoMaxX; x++)
    324             if (!logoMask[y * width + x] == 1)
    325                 pixels++;
    326 
    327     if (pixels < 30)
    328         return;
    329 
    330     // set the pixels around our logo
    331     for(unsigned int y = (logoMinY - 1); y <= (logoMaxY + 1); y++)
    332     {
    333         for(unsigned int x = (logoMinX - 1); x <= (logoMaxX + 1); x++)
    334         {
    335             if (!logoMask[y * width + x])
     201            else
    336202            {
    337                 for (unsigned int y2 = y - 1; y2 <= (y + 1); y2++)
    338                 {
    339                     for (unsigned int x2 = x - 1; x2 <= (x + 1); x2++)
    340                     {
    341                         if ((logoMask[y2 * width + x2] == 1) &&
    342                             (!logoMask[y * width + x]))
    343                         {
    344                             logoMask[y * width + x] = 2;
    345                             x2 = x + 2;
    346                             y2 = y + 2;
    347 
    348                             logoCheckMask[y2 * width + x2] = 1;
    349                             logoCheckMask[y * width + x] = 1;
    350                         }
    351                     }
    352                 }
     203                tmpMask[pos] = false;
    353204            }
    354         }
    355     }
    356 
    357     for(unsigned int y = (logoMinY - 2); y <= (logoMaxY + 2); y++)
     205        } // end for x
     206    } // end for y
     207   
     208    logoMinX -= 1;
     209    logoMaxX += 1;
     210    logoMinY -= 1;
     211    logoMaxY += 1;
     212
     213    if (logoMinX < commDetectBorder)
     214        logoMinX = commDetectBorder;
     215    if (logoMaxX > (width-commDetectBorder))
     216        logoMaxX = (width-commDetectBorder);
     217    if (logoMinY < commDetectBorder)
     218        logoMinY = commDetectBorder;
     219    if (logoMaxY > (height-commDetectBorder))
     220        logoMaxY = (height-commDetectBorder);
     221   
     222    if (pixelsInMask > 0 && logoMaxX > logoMinX && logoMaxY > logoMinY)
    358223    {
    359         for(unsigned int x = (logoMinX - 2); x <= (logoMaxX + 2); x++)
     224        logoWidth = logoMaxX - logoMinX;
     225        logoHeight = logoMaxY - logoMinY;
     226       
     227        edgeMask.resize(logoWidth * logoHeight);
     228        for (unsigned int y = 0; y < logoHeight; ++y)
    360229        {
    361             if (!logoMask[y * width + x])
     230            for (unsigned int x = 0; x < logoWidth; ++x)
    362231            {
    363                 for (unsigned int y2 = y - 1; y2 <= (y + 1); y2++)
    364                 {
    365                     for (unsigned int x2 = x - 1; x2 <= (x + 1); x2++)
    366                     {
    367                         if ((logoMask[y2 * width + x2] == 2) &&
    368                             (!logoMask[y * width + x]))
    369                         {
    370                             logoMask[y * width + x] = 3;
    371                             x2 = x + 2;
    372                             y2 = y + 2;
    373 
    374                             logoCheckMask[y * width + x] = 1;
    375                         }
    376                     }
    377                 }
     232                edgeMask[y * logoWidth + x] = tmpMask[(y + logoMinY) * width + (x + logoMinX)];
    378233            }
    379234        }
    380235    }
    381 
    382 #ifdef SHOW_DEBUG_WIN
    383     DumpLogo(true,framePtr);
    384 #endif
    385 
    386     logoFrameCount = 0;
    387     logoInfoAvailable = true;
     236   
     237    return pixelsInMask;
    388238}
    389239
    390 
    391 void ClassicLogoDetector::DumpLogo(bool fromCurrentFrame,
    392     unsigned char* framePtr)
     240void ClassicLogoDetector::DumpLogo()
    393241{
    394     char scrPixels[] = " .oxX";
    395 
    396     if (!logoInfoAvailable)
    397         return;
    398 
    399     cerr << "\nLogo Data ";
    400     if (fromCurrentFrame)
    401         cerr << "from current frame\n";
    402 
    403     cerr << "\n     ";
    404 
    405     for(unsigned int x = logoMinX - 2; x <= (logoMaxX + 2); x++)
    406         cerr << (x % 10);
    407     cerr << "\n";
    408 
    409     for(unsigned int y = logoMinY - 2; y <= (logoMaxY + 2); y++)
     242    cerr << "Logo data (" << logoMinX << "," << logoMinY << ") x ("
     243                          << logoWidth << "," << logoHeight << ") @ "
     244                          << logoEdgeDiff << ":\n";
     245   
     246    for (unsigned int y = 0; y < logoHeight; y++)
    410247    {
    411         QString tmp = QString("%1: ").arg(y, 3);
    412         QString ba = tmp.toAscii();
    413         cerr << ba.constData();
    414         for(unsigned int x = logoMinX - 2; x <= (logoMaxX + 2); x++)
     248        for (unsigned int x = 0; x < logoWidth; x++)
    415249        {
    416             if (fromCurrentFrame)
    417             {
    418                 cerr << scrPixels[framePtr[y * width + x] / 50];
    419             }
     250            unsigned int pos = y * logoWidth + x;
     251            if (edgeMask[pos])
     252                cerr << "#";
    420253            else
    421             {
    422                 switch (logoMask[y * width + x])
    423                 {
    424                         case 0:
    425                         case 2: cerr << " ";
    426                         break;
    427                         case 1: cerr << "*";
    428                         break;
    429                         case 3: cerr << ".";
    430                         break;
    431                 }
    432             }
     254                cerr << " ";
    433255        }
    434256        cerr << "\n";
    435257    }
    436     cerr.flush();
     258   
     259    cerr << "\n\n\n";
    437260}
    438261
     262bool ClassicLogoDetector::pixelInsideLogo(unsigned int x, unsigned int y)
     263{
     264    if (!logoInfoAvailable)
     265        return false;
     266   
     267    int xd = x - logoMinX;
     268    int yd = y - logoMinY;
     269   
     270    return xd >= 0 && xd < (int)logoWidth &&
     271           yd >= 0 && yd < (int)logoHeight;
     272}
    439273
    440 /* ideas for this method ported back from comskip.c mods by Jere Jones
    441  * which are partially mods based on Myth's original commercial skip
    442  * code written by Chris Pinkham. */
    443 bool ClassicLogoDetector::doesThisFrameContainTheFoundLogo(
    444     unsigned char* framePtr)
     274bool ClassicLogoDetector::isSobelEdgeAt(unsigned char *buf,
     275                                        unsigned int x,
     276                                        unsigned int y,
     277                                        unsigned int width,
     278                                        unsigned char edgeDiff)
    445279{
    446     int radius = 2;
    447     unsigned int x, y;
    448     int pos1, pos2, pos3;
    449     int pixel;
    450     int goodEdges = 0;
    451     int badEdges = 0;
    452     int testEdges = 0;
    453     int testNotEdges = 0;
     280    int center = y * width + x;
     281    int above = center - width;
     282    int below = center + width;
     283   
     284    int gx = 0;
     285    gx -= buf[above - 1];
     286    gx -= (buf[center - 1]*2);
     287    gx -= buf[below - 1];
     288   
     289    gx += buf[above + 1];
     290    gx += (buf[center + 1]*2);
     291    gx += buf[below + 1];
     292   
     293    int gy = 0;
     294    gy -= buf[above - 1];
     295    gy -= (buf[above]*2);
     296    gy -= buf[above + 1];
     297   
     298    gy += buf[below - 1];
     299    gy += (buf[below]*2);
     300    gy += buf[below + 1];
     301   
     302    return abs(gx) + abs(gy) > 3*edgeDiff;
     303}
    454304
    455     for (y = logoMinY; y <= logoMaxY; y++ )
     305bool ClassicLogoDetector::doesThisFrameContainTheFoundLogo(unsigned char *framePtr)
     306{
     307    if (!logoInfoAvailable)
     308        return false;
     309   
     310    unsigned int x, y;
     311    unsigned int correct = 0, total = 0;
     312   
     313    for (y = 0; y < logoHeight; y++ )
    456314    {
    457         for (x = logoMinX; x <= logoMaxX; x++ )
     315        for (x = 0; x < logoWidth; x++ )
    458316        {
    459             pos1 = y * width + x;
    460             pos2 = (y - radius) * width + x;
    461             pos3 = (y + radius) * width + x;
    462 
    463             pixel = framePtr[pos1];
    464 
    465             if (edgeMask[pos1].horiz)
    466             {
    467                 if ((abs(framePtr[pos1 - radius] - pixel) >= logoEdgeDiff) ||
    468                     (abs(framePtr[pos1 + radius] - pixel) >= logoEdgeDiff))
    469                     goodEdges++;
    470                 testEdges++;
    471             }
    472             else
    473             {
    474                 if ((abs(framePtr[pos1 - radius] - pixel) >= logoEdgeDiff) ||
    475                     (abs(framePtr[pos1 + radius] - pixel) >= logoEdgeDiff))
    476                     badEdges++;
    477                 testNotEdges++;
    478             }
    479 
    480             if (edgeMask[pos1].vert)
    481             {
    482                 if ((abs(framePtr[pos2] - pixel) >= logoEdgeDiff) ||
    483                     (abs(framePtr[pos3] - pixel) >= logoEdgeDiff))
    484                     goodEdges++;
    485                 testEdges++;
    486             }
    487             else
     317            if (edgeMask[y * logoWidth + x])
    488318            {
    489                 if ((abs(framePtr[pos2] - pixel) >= logoEdgeDiff) ||
    490                     (abs(framePtr[pos3] - pixel) >= logoEdgeDiff))
    491                     badEdges++;
    492                 testNotEdges++;
     319                if (isSobelEdgeAt(framePtr, x + logoMinX, y + logoMinY, width, logoEdgeDiff))
     320                    correct++;
     321                total ++;
    493322            }
    494323        }
    495324    }
    496 
    497     frameNumber++;
    498     double goodEdgeRatio = (double)goodEdges / (double)testEdges;
    499     double badEdgeRatio = (double)badEdges / (double)testNotEdges;
    500     if ((goodEdgeRatio > commDetectLogoGoodEdgeThreshold) &&
    501         (badEdgeRatio < commDetectLogoBadEdgeThreshold))
    502         return true;
    503     else
    504         return false;
    505 }
    506 
    507 bool ClassicLogoDetector::pixelInsideLogo(unsigned int x, unsigned int y)
    508 {
    509     if (!logoInfoAvailable)
    510         return false;
    511 
    512     return ((x > logoMinX) && (x < logoMaxX) &&
    513             (y > logoMinY) && (y < logoMaxY));
     325   
     326    double d = (double)correct / (double)total;
     327    return d >= commDetectLogoGoodEdgeThreshold;
    514328}
    515329
    516 void ClassicLogoDetector::DetectEdges(VideoFrame *frame, EdgeMaskEntry *edges,
    517                                       int edgeDiff)
     330void ClassicLogoDetector::DetectEdges(VideoFrame *frame, int *edgeCounts, int edgeDiff)
    518331{
    519     int r = 2;
    520     unsigned char *buf = frame->buf;
    521     unsigned char p;
    522     unsigned int pos, x, y;
    523 
    524     for (y = commDetectBorder + r; y < (height - commDetectBorder - r); y++)
     332    unsigned int x, y;
     333   
     334    unsigned int hOneThird = height / 3;
     335    unsigned int hTwoThirds = hOneThird*2;
     336    unsigned int wOneThird = width / 3;
     337    unsigned int wTwoThirds = wOneThird*2;
     338   
     339    for (y = commDetectBorder; y < height - commDetectBorder; ++y)
    525340    {
    526         if ((y > (height/4)) && (y < (height * 3 / 4)))
    527             continue;
    528 
    529         for (x = commDetectBorder + r; x < (width - commDetectBorder - r); x++)
     341        for (x = commDetectBorder; x < width - commDetectBorder; ++x)
    530342        {
    531             int edgeCount = 0;
    532 
    533             if ((x > (width/4)) && (x < (width * 3 / 4)))
    534                 continue;
    535 
    536             pos = y * width + x;
    537             p = buf[pos];
    538 
    539             if (( abs(buf[y * width + (x - r)] - p) >= edgeDiff) ||
    540                 ( abs(buf[y * width + (x + r)] - p) >= edgeDiff))
    541             {
    542                 edges[pos].horiz++;
    543                 edgeCount++;
    544             }
    545             if (( abs(buf[(y - r) * width + x] - p) >= edgeDiff) ||
    546                 ( abs(buf[(y + r) * width + x] - p) >= edgeDiff))
    547             {
    548                 edges[pos].vert++;
    549                 edgeCount++;
    550             }
    551 
    552             if (( abs(buf[(y - r) * width + (x - r)] - p) >= edgeDiff) ||
    553                 ( abs(buf[(y + r) * width + (x + r)] - p) >= edgeDiff))
     343            if (y > hOneThird && y < hTwoThirds &&
     344                x > wOneThird && x < wTwoThirds)
    554345            {
    555                 edges[pos].ldiag++;
    556                 edgeCount++;
     346                x = wTwoThirds - 1;
    557347            }
    558 
    559             if (( abs(buf[(y - r) * width + (x + r)] - p) >= edgeDiff) ||
    560                 ( abs(buf[(y + r) * width + (x - r)] - p) >= edgeDiff))
     348            else if (isSobelEdgeAt(frame->buf, x, y, width, edgeDiff))
    561349            {
    562                 edges[pos].rdiag++;
    563                 edgeCount++;
     350                edgeCounts[y * width + x]++;
    564351            }
    565 
    566             if (edgeCount >= 3)
    567                 edges[pos].isedge++;
    568352        }
    569353    }
    570354}
    571355
    572356/* vim: set expandtab tabstop=4 shiftwidth=4: */
    573 
  • mythtv/programs/mythcommflag/ClassicLogoDetector.h

    diff --git a/mythtv/programs/mythcommflag/ClassicLogoDetector.h b/mythtv/programs/mythcommflag/ClassicLogoDetector.h
    index d589df5..a78ce4c 100644
    a b  
    22#define _CLASSICLOGOGEDETECTOR_H_
    33
    44#include "LogoDetectorBase.h"
     5#include <qbitarray.h>
    56
    6 typedef struct edgemaskentry EdgeMaskEntry;
    77typedef struct VideoFrame_ VideoFrame;
    88class ClassicCommDetector;
    99
    class ClassicLogoDetector : public LogoDetectorBase 
    1616    virtual void deleteLater(void);
    1717
    1818    bool searchForLogo(MythPlayer* player);
    19     bool doesThisFrameContainTheFoundLogo(unsigned char* frame);
     19    bool doesThisFrameContainTheFoundLogo(unsigned char *framePtr);
    2020    bool pixelInsideLogo(unsigned int x, unsigned int y);
    2121
    2222    unsigned int getRequiredAvailableBufferForSearch();
    2323
     24    void DumpLogo();
     25    static bool isSobelEdgeAt(unsigned char *buf, unsigned int x, unsigned int y, unsigned int width, unsigned char edgeDiff);
     26   
    2427  protected:
    2528    virtual ~ClassicLogoDetector() {}
    2629
    2730  private:
    28     void SetLogoMaskArea();
    29     void SetLogoMask(unsigned char *mask);
    30     void DumpLogo(bool fromCurrentFrame,unsigned char* framePtr);
    31     void DetectEdges(VideoFrame *frame, EdgeMaskEntry *edges, int edgeDiff);
    32 
     31    int AnalyzeEdgeCounts(int *edgeCounts, int threshold);
     32    void DetectEdges(VideoFrame *frame, int *edgeCounts, int edgeDiff);
     33   
    3334    ClassicCommDetector* commDetector;
    34     unsigned int frameNumber;
    35     bool previousFrameWasSceneChange;
    36     unsigned int xspacing, yspacing;
    3735    unsigned int commDetectBorder;
    38 
     36   
    3937    int commDetectLogoSamplesNeeded;
    4038    int commDetectLogoSampleSpacing;
    4139    int commDetectLogoSecondsNeeded;
    4240    double commDetectLogoGoodEdgeThreshold;
    4341    double commDetectLogoBadEdgeThreshold;
     42   
     43    QBitArray edgeMask;
    4444
    45     EdgeMaskEntry *edgeMask;
    46 
    47     unsigned char *logoMaxValues;
    48     unsigned char *logoMinValues;
    49     unsigned char *logoFrame;
    50     unsigned char *logoMask;
    51     unsigned char *logoCheckMask;
    52     unsigned char *tmpBuf;
    53 
     45    bool logoInfoAvailable;   
    5446    int logoEdgeDiff;
    55     unsigned int logoFrameCount;
    5647    unsigned int logoMinX;
    57     unsigned int logoMaxX;
     48    unsigned int logoWidth;
    5849    unsigned int logoMinY;
    59     unsigned int logoMaxY;
    60 
    61     bool logoInfoAvailable;
     50    unsigned int logoHeight;
    6251};
    6352
    6453#endif